我在 Windows 10 主機上的 Hyper-V 中安裝了 Ubuntu 18.04,並在某些連接埠上公開了功能,這些連接埠可供主機上執行的其他程式存取時使用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
文件,其中包含所有正在執行的 VM 的 IP 位址和 VM 名稱:
get-vm | Get-VMNetworkAdapter | ? IPAddresses -ne $null | % {Write-Output "$($_.ipaddresses[0]) $($_.VMName)"} | Set-Content -Path ".\hosts"
需要注意的幾點:
該腳本需要以管理員身份執行。
這設定內容 命令需要更好的 Path 參數,因為目前它將覆蓋
hosts
目前資料夾中的檔案。如果您不想
hosts
覆蓋文件而是附加文件,請使用 添加內容 命令代替。這樣您就可以從初始hosts
文件開始並附加到它。這 寫入輸出 命令輸出該欄位中的第一個條目
ipaddresses
。如果同時啟用 IPv4 和 IPv6,則清單將包含兩個條目,其中第一個條目通常是 IPv4 的條目。
hosts
透過此腳本為我正在運行的虛擬機器生成的範例文件:
172.17.223.121 Windows10Test
(最好避免在虛擬機器名稱中出現空格,否則腳本上需要做更多工作。)
答案2
在 Windows HOSTS 檔案中新增 IP 位址。完整路徑是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
欲了解更多信息,請閱讀維基百科:主機(文件)。
答案3
我找到了一種透過名稱從其他來賓虛擬機器或主機連接到來賓虛擬機器的方法,使用由 Hyper-V 自動管理的名稱,如下所示:
- 將來賓連接到預設交換器(這是新虛擬機器的預設交換器)。
- 將 IP 位址設定為來賓上的 DHCP(這是新 VM 的預設)。
- 將來賓作業系統中的電腦名稱/主機名稱設定為唯一的名稱,例如
myfirstvm
。 DNS 後綴並不重要。 - 從另一個虛擬機器或主機,嘗試聯繫
<host_name>.mshome.net
,例如,如果您將主機名稱設定為myfirstvm
,請嘗試myfirstvm.mshome.net
從主機執行 ping 操作。
解釋:
hosts
在我的系統上,我在與名為 的檔案相同的目錄中找到了一個檔案hosts.ics
。它似乎包含我所有客人的條目Default Switch
和基本系統的條目,但都帶有後綴mshome.net
。我相信連接到預設交換器的網路介面卡使用 Internet 連線共用功能,該功能會自動建立和維護此hosts.ics
檔案。當您的用戶端啟動時,它會透過 DHCP 請求 IP 位址,並嘗試向 Hyper-V 內建的 DNS 伺服器註冊自身。我相信 Hyper-V 會採用來賓嘗試註冊的名稱並將其儲存在該hosts.ics
文件中,並使用新的後綴mshome.net
.如果您的兩台來賓虛擬機器都嘗試註冊相同的名稱,則此程序將中斷。
不確定這是一個新功能還是一直存在。發現於 Windows 11 Pro、Hyper-V 10.0.22000.1
答案4
此 powershell 腳本建置於盧克·施拉瑟的回答(https://superuser.com/a/1485949/280673)對於這個問題。
最重要的區別是,它不會使用虛擬機器 IP 位址覆蓋整個主機文件,而是在存在新虛擬機器時附加新條目並覆蓋先前存在的條目的位址。這應該消除了進行備份的需要,並保留了您可能為本機開發或其他目的而建立的主機檔案中的其他條目。
#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 上,您可以從 HyperV 和 powershell 中挖掘出指派給虛擬機器的 IP。這可能會因不同的作業系統而異,因此如果您無法從主機端取得位址,您可能必須尋找適合您的系統的指南(或發布新問題)。
我留下了備份部分,只是將其註解掉,以便更輕鬆地試驗和迭代腳本。另外,如果需要在更合理的位置進行備份,也可以更輕鬆地進行備份(如果沒有進行任何更改,則不需要備份,因此在寫入更改之前不要進行備份)。
我還將關於替換地址的正則表達式如何在程式碼中工作的評論,而不是在帖子正文的外部。這是為了在複製貼上後丟失這篇文章的引用時更容易遵循程式碼,並且希望在有人想要對其進行更改時有所幫助。