Virtual Machine - 虛擬機
虛擬機(Virtual Machine)指通過軟件模擬的具有完整硬件系統功能的、運行在一個完全隔離環境中的完整計算機系統。
在很多場景下,我們都會需要用到虛擬機:
- 測試、嘗鮮新系統。
- 完全隔離的沙箱環境,用於運行某些不安全的或者敏感的文件/程序。
- 雲服務商或企業會通過服務器虛擬化,提升服務器的利用率。
- 虛擬機可以創建快照,系統環境可以隨時還原到已有的快照,也能方便地拷貝給他人。(有點類似 docker 鏡像,但是沒有標准化的 dockerfile 定義文件)
桌面虛擬化軟件
桌面虛擬化軟件,就是提供 UI 界面的,使用很方便的虛擬化軟件。通常直接安裝在個人的桌面 PC 上。
- VMware Workstation: 閉源收費軟件,但是網上許可證一大堆。
- VirtualBox: 免費開源,但是 UI 沒 VMware 好看。
- QEMU/KVM: 用 qemu/kvm+virt-manager 做桌面虛擬化,性能是最好的,但是有一定門檻,適合專業人員。
- 它沒有做到像 vmware/virtualbox 那樣簡單易懂,有一定學習門檻。
- 深入使用,需要熟悉 libvirtd 的命令行和 xml.
服務器虛擬化 - Hypervisor
服務器虛擬化軟件,也叫 Hypervisor——虛擬機管理程序,有時也稱做 Virtual Machine Monitor(VMM),它可以在宿主機上創建並管理多個虛擬機。
目前比較流行的 Hypervisor 有:
-
vShpere Hypervisor: 也就是 ESXi,這是一個閉源收費的服務器虛擬化系統。基於 Linux,可直接安裝在物理機上。
- 優點是簡單方便,但是收費。適合中小企業,或者個人搭着玩。
- 成熟穩定,用戶眾多。但是各大雲服務提供商全都用 KVM 做了自己的虛擬化平台,因為免費且自主可控。
- ESXi 搭配 vCenter 可以中心化地管理 ESXi 集群,搭配 terraform/python sdk 可以實現虛擬機的自動化創建等功能。
-
ProxmoxVE: 一個開源免費的服務器虛擬化系統,基於 Debian + QEMU/KVM + LXC.
- PVE 開源免費,而 VMware 的全套技術都是閉源收費的
- PVE 底層是 QEMU/KVM,存儲方案也是 Ceph/iSCSI/NFS/LVM 這些都是使用很廣泛的開源技術,對提升個人及公司的技術能力有很大幫助。
- PVE 支持 cloudinit,這是一個虛擬機的預配置工具,可以用於預配置網絡、磁盤擴容、設置 hostname 等,非常方便!
- 文檔齊全,而且很接地氣,還包含許多 QEMU/KVM/CEPH/Cloudinit 等開源技術的內容。 反觀 VMware 的文檔,真的是寫得爛得一批,不知所雲,隨便找篇博客都要比官方文檔好理解得多。
- 提供一套方便的 CLI 工具,以及 RESTful API。不論是 CLI 還是 HTTP API/Python SDK 都比 vmware 先進很多。VMware 的 python sdk 真的是超級難用,印象深刻。
- 缺點在於,PVE 的 WebUI 功能不全,有些功能必須通過命令行才能實現。(這和路由器類似,高級功能只有 CLI 支持)
-
KVM+OpenStack: 難度較高(openstack 我還沒用過)。適合進階用戶,或者大廠自己 DIY。
所以廢話不多說,接下來進入 PVE 實操。
安裝 PVE
安裝過程沒啥好說的,安裝好后,需要按下面這篇文章配置國內鏡像源,啟用 root 賬戶 ssh 登錄:
# 設置 debian 的阿里鏡像源
cp /etc/apt/sources.list /etc/apt/sources.list.bak
sed -i "s@\(deb\|security\).debian.org@mirrors.aliyun.com@g" /etc/apt/sources.list
# 去除煩人的訂閱提示
sed -i "s/data.status !== 'Active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
# 設置 pve 國內鏡像源
# https://mirrors.bfsu.edu.cn/help/proxmox/
echo 'deb https://mirrors.bfsu.edu.cn/proxmox/debian buster pve-no-subscription' > /etc/apt/sources.list.d/pve-no-subscription.list
使用 Cloud-Init 自動配置網卡、SSH密鑰、存儲大小配置
完全參照官方文檔 Cloud-Init_Support - PVE Docs
首先下載 Cloud 版本的系統鏡像:
- CentOS Cloud 版本: 提供 qcow2 格式的鏡像
- Debian Cloud Images: 也提供 qcow2 格式的鏡像
- Ubuntu Cloud Images (RELEASED): 提供 img 格式的裸鏡像(PVE 也支持此格式)
- 注意:需要下載帶有 kvm 字樣的鏡像!
- OpenSUSE Cloud Images
- 注意:請下載帶有 openstack 和 x86_64 字樣的鏡像
上述鏡像和我們普通虛擬機使用的 ISO 鏡像的區別,一是鏡像格式不同,二是都自帶了 cloud-init/qemu-guest-agent/cloud-utils-growpart 等 cloud 相關軟件。
上述三個 cloud 鏡像的默認名稱和系統名稱完全一致,分別為 centos
/debian
/ubuntu
,
均沒有默認密碼,並且禁用了 SSH 密碼登錄,必須通過 cloud-init 設置私鑰方式進行遠程登錄。
建議在 cloud-init 配置中自行設置賬號與私鑰,不要使用默認的賬號名。
比如測試環境,可以直接設置賬號為 root,並設置相應的私鑰。
接下來我們需要將得到的 qcow2 鏡像導入 PVE,並用它創建一個虛擬機模板。
首先創建虛擬機,並以導入的磁盤為該虛擬機的硬盤
# 創建新虛擬機
qm create 9000 --name ubuntu-bionic-template --memory 2048 --net0 virtio,bridge=vmbr0
# 將下載好的 img/qcow2 鏡像導入為新虛擬機的硬盤
qm importdisk 9000 ubuntu-20.10-server-cloudimg-amd64.img local-lvm
# 通過 scsi 方式,將導入的硬盤掛載到虛擬機上
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
# 創建一個 cloud-init 需要使用的 CDROM 盤(sr0)
qm set 9000 --ide2 local-lvm:cloudinit
# 設置系統引導盤
qm set 9000 --boot c --bootdisk scsi0
# 設置 serial0 為顯示終端,很多雲鏡像都需要這個。(?感覺我不需要?)
qm set 9000 --serial0 socket --vga serial0
后續配置:
- 手動設置 cloud-init 配置,啟動虛擬機,並通過 ssh 登入遠程終端。
- 檢查 qemu-guest-agent,如果未自帶,一定要手動安裝它!
- 安裝所需的基礎環境,如 docker/docker-compose/vim/git/python3
- 關閉虛擬機,然后將虛擬機設為模板(只讀)。
- 接下來就可以從這個模板虛擬機,克隆各類新虛擬機了~
cloud-init 高級配置
PVE 使用 CDROM 只讀盤(/dev/sr0)來進行 cloud-init 的配置。
在虛擬機啟動后,/dev/sr0 將被卸載。
可掛載上該只讀盤,查看其中的初始化配置內容:
$ mkdir cloud-config
$ mount /dev/sr0 cloud-config
mount: /dev/sr0 is write-protected, mounting read-only
$ ls cloud-config
meta-data network-config user-data
查看上述文件發現 user-data
有如下問題:
- 它硬編碼了
manage_etc_hosts: true
,這導致我手動在/etc/cloud/cloud.cfg
里設定的manage_etc_hosts: false
被覆蓋。 - 它設置了
hostname: <vm-name>
- cloud-init 的默認策略是
preserve_hostname: false
,表示不維持對hostname
的修改。 - 默認策略的實際行為:每次虛擬機啟動時,cloud-init 都會自動將
/etc/hostname
還原為user-data
中的hostname
/fqdn
. - 這使任何對
/etc/hostname
的手動修改,都是臨時的,重啟就會被還原為user-data
中設置的hostname
.
- cloud-init 的默認策略是
修改 cloud-init 相關的硬編碼參數
通過前面的排查,我們發現 proxmox 有很多參數都硬編碼了,沒有通過配置暴露出來,導致我們無法修改。
為了解決這個問題,我們完全可以修改掉 PVE 代碼里的硬編碼參數。
首先通過全文搜索,找到硬編碼參數的位置:
# 在 /usr/share 中全文搜索 manage_etc_hosts 這個關鍵字
grep -r manage_etc_hosts /usr/share
直接就搜索到了硬編碼位置是 /usr/share/perl5/PVE/QemuServer/Cloudinit.pm
-
手動將配置修改為
manage_etc_hosts: localhost
,就能讓 cloud-init 只更新 localhost 相關的 hosts 內容。 -
如果希望對 hostname 的手動修改能永久生效,可以添加參數
preserve_hostname: true
.- 注意這樣設置后,cloud-init 的
set_hostname
/update_hostname
兩個模塊將不會修改 hostname!
- 注意這樣設置后,cloud-init 的
對上述文件的修改需要重啟 PVE 后,才能生效(因為 perl 程序才啟動后代碼就加載到內存中了,改文件對內存中的對象沒有影響)。
解決 SSH 登錄速度慢的問題
貌似所有的 cloud-init 的虛擬機,SSH 都存在速度慢的問題。
關閉掉 ssh server 的反向 DNS 解析,可以解決這個問題:
echo "UseDNS no" >> /etc/ssh/sshd_config
虛擬機硬盤擴容
CentOS/Ubuntu/Debian 提供的 Cloud 鏡像,都自帶了 cloud-utils-growpart 這個組件,可以實現在擴容物理硬盤時,自動調整 Linux 的分區大小。
因此需要擴容虛擬機時,直接通過 UI 面板/命令行擴容虛擬機的硬盤即可, Linux 的分區會被 cloud-utils-growpart 自動擴容。
因為這個方便的特性,也為了減少虛擬化的開銷,Cloud 鏡像默認是不使用 LVM 邏輯分區的。
LVM 邏輯分區雖然方便,但是它對物理機的作用更大些。虛擬機因為本身就能動態擴容“物理硬盤”的大小,基本不用不到 LVM。
還有一點,就是虛擬機通常只需要一個根分區就行,尤其是歸 openstack/kubernetes 管的虛擬機。
只有在使用分布式存儲之類的場景下,數據需要獨立存儲,才需要用到額外的分區(/data 之類的)。
一般只有物理機,才需要像網上很多文章提的那樣,為 /boot / /home 去單獨分區。
而且現在大家都用 SSD 了,物理機這樣做分區的都少了,比如我個人電腦,就是一個 / 分區打天下。。。
自動化工具
- terraform-provider-proxmox: 詳情參見 terraform - infrastructure
- Python SDK
監控告警
- prometheus pve expoter: 通過 prometheus+grafana 監控 PVE 集群
常見問題
1. 導入已有的 qcow2 鏡像
必須要命令行操作
先通過 scp 將 qcow2 傳輸到 PVE 上,然后命令行使用如下命令導入鏡像:
# 命令格式
qm importdisk <vmid> <source> <storage>
# 示例
qm importdisk 201 vm-201-disk-1.qcow2 local-lvm
導入完成后,在 WebUI 界面的左側會看到多了一個「未使用的磁盤 0」,
現在新建一台新虛擬機,然后刪除掉默認的磁盤(分離+刪除,要兩步),然后掛載這個「未使用的磁盤 0」就大功告成了。