PVE(Proxmox VE)

PVETOOLS

pvetools主要用于pvetools换源,去订阅信息,显示温度,调整cpu功率等

使用前强烈建议先删除企业源

rm /etc/apt/sources.list.d/pve-enterprise.list

安装pvetools

官网源

export LC_ALL=en_US.UTF-8
apt update && apt -y install git && git clone https://github.com/ivanhao/pvetools.git
cd pvetools
./pvetools.sh

国内镜像源

export LC_ALL=en_US.UTF-8
apt update && apt -y install git && git clone https://gitee.com/ZBingK/pvetools.git
cd pvetools
./pvetools.sh

PVE手动换源

pve 8.x的源

echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list

pve 7.x

echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/pve bullseye pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list

替换ct源

sed -i.bak 's|http://download.proxmox.com|https://mirrors.ustc.edu.cn/proxmox|g' /usr/share/perl5/PVE/APLInfo.pm
#换源后重启web服务,不影响虚拟机运行
systemctl restart pvedaemon

修改web默认语言

编辑文件nano /etc/pve/datacenter.cfg

keyboard: en-us  #默认应该有这一行
language: zh_CN  #添加这一行,修改默认为简体中文,zh_TW为繁体中文

硬件直通

DANGER

所有硬件直通均可能导致系统开机异常,直通前务必关闭所有虚拟机自启动

首先进入bios,打开vt-x及vt-d 编辑grub

nano /etc/default/grub
# intel cpu
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on video=efifb:off"
# amd cpu
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on video=efifb:off"
# 更新grub
update-grub

打开虚拟机-硬件-添加pci设备

可以用lspci列出所有pci设备

以下为一些常用的pci设备

集成显卡一般为00:02

硬盘控制器 以SATANvme为主

挂载物理硬盘

查看已有硬盘比如我想挂载/dev/sda 和/dev/sdb到虚拟机100 记录这两个值,然后进行shell pve-idm

ls /dev/disk/by-id/    #用id方式显示硬盘,后缀带part的是分区,也可以只挂载某一个分区
> ata-WDC_WD20EARZ-00C5XB0_WD-WX72D43AWV52
> ata-WDC_WD20EARZ-00C5XB0_WD-WX72D43AWV52-part1
> ata-WDC_WD20EARZ-00C5XB0_WD-WX72D43AWV52-part2
> ata-WDC_WD20EARZ-00C5XB0_WD-WX72D43AWV52-part3
> ata-WDC_WD20EARZ-00C5XB0_WD-WXU2A23C9Z4R
> ata-WDC_WD20EARZ-00C5XB0_WD-WXU2A23C9Z4R-part1
> ata-WDC_WD20EARZ-00C5XB0_WD-WXU2A23C9Z4R-part2
> ata-WDC_WD20EARZ-00C5XB0_WD-WXU2A23C9Z4R-part3
# 将两个物理硬盘挂载到虚拟机100 sata1和sata2必须为未使用的硬盘看,可以在虚拟机100硬件中查看
qm set 100 --sata1 /dev/disk/by-id/ata-WDC_WD20EARZ-00C5XB0_WD-WX72D43AWV52
qm set 100 --sata2 /dev/disk/by-id/ata-WDC_WD20EARZ-00C5XB0_WD-WXU2A23C9Z4R

VMWare/ESXI 迁移到 PVE

  1. VMWare 界面将虚拟机关机,然后导出虚拟机,只需要vmdk硬盘即可
  2. 登录pve,创建新虚拟机记录虚拟机ip,如2000并删除现有硬盘
  3. 上传vmdk,建议用sftp上传
  4. 执行命令,导入硬盘后,在硬件选中未添加的硬盘,编辑-添加
qm importdisk 2000 /root/demo.vmdk local-lvm 

#推荐 qcow2 可以快照
qm importdisk 2000 /root/demo.vmdk local --format qcow2                                  

添加硬盘
5. 修改引导顺序 ,选项-引导顺序 引导顺序

PVE 迁移到 VMWare

PVE 界面上没有将虚拟机导出为 vmdk 文件的途径,只能到 PVE 宿主机的 SHELL 环境里操作。在操作之前得先找到虚拟机所在磁盘,在 PVE 管理页面找到虚拟机配置里磁盘名称,比如 "vm-2002-disk-0",再到 SHELL 下执行下面的命令:

# 找到虚拟机所在磁盘
find / -name vm-2002-disk-0
> /dev/pve/vm-2002-disk-0

# 上面的 /dev/pve/vm-2002-disk-0 实际上是一个链接文件
ls -l /dev/pve/vm-2002-disk-0
> lrwxrwxrwx 1 root root 8 Mar  2 07:07 /dev/pve/vm-2002-disk-0 -> ../dm-10

# 查看实际文件,看到有个 b 标志,表示这是一个块设备文件
ls -l /dev/dm-10
> brw-rw---- 1 root disk 253, 10 Mar  2 07:52 /dev/dm-10

# 用 qemu-img 命令转换,源格式自动判断,目的格式是 vmdk
qemu-img convert -f raw -O vmdk /dev/dm-10 /dev/vm10.vmdk
ls -lh /dev/vm10.vmdk
> -rw-r--r-- 1 root root 7.3G Mar  2 08:03 /dev/vm10.vmdk

得到 vmdk 文件后就简单了,拷贝出来,载入到 VMWare 环境即可

常用命令

systemctl restart pve-cluster
systemctl restart pvedaemon
systemctl restart pveproxy
systemctl restart pvestatd

常见问题处理

PVE修改IP

要改三个地方

nano /etc/network/interfaces
nano /etc/issue
nano /etc/hosts

can't lock file 问题解决

有些时候操作主机重启或停止显示 "can't lock file" 并且拒绝后续操作,可以到命令行界面下执行下面的命令:

# 先看看有没有对应 vmid 的 lock 文件,手工删除
ls -l /run/lock/qemu-server

qm unlock $vmid
rm /run/lock/qemu-server/lock-$vmid.conf

centos7 lxc允许

nano /etc/default/grub      #修改 grub,添加下面内容
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=0"

update-grub     #更新引导
reboot          #重启

smb挂载失败

<>及里面的文字都需要替换掉

pvesm add cifs <挂载名称> --server <smb服务器ip> \
--share <文件夹名> \
--username <用户名> \
--password <密码> \
--smbversion 2.0

webAPI

度娘,谷歌都搜了一圈没有找到通过PVE API创建虚拟机的方式, 于是查官网自己试了试,部分代码抄的Sam Liu大佬的作业,感谢大佬。 python代码如下:

import requests
# self-sign CA warning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class Pve_api(object):

    def __init__(self, ip, username = None, password = None, port = '8006'):
        self.ip = ip
        self.username = username
        self.password = password
        self.port = port
        self.ticket = None

    '''
    ####### ticket data structure
    {
    "data":{
    "ticket": "PVE:root@pam:xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "cap":{"vms":{"VM.Clone": 1, "VM.Backup": 1, "VM.Config.Options": 1, "VM.Snapshot": 1,…},
    "CSRFPreventionToken": "6xxxxxx:/xxxxxxxxxxxxxxxx",
    "username": "root@pam"
    }
    }

    '''

    #获取ticket
    def get_ticket(self):
        path = '/api2/json/access/ticket'
        url = 'https://' + self.ip + ':' + self.port + path
        r = requests.post(url=url, json={"username": self.username, "password": self.password}, verify=False)
        self.ticket = r.json() # dict rather than string
        return r.json()
    #查询节点列表
    def ticket_node_list(self):
        path = '/api2/json/nodes'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()

    #查询虚拟机列表
    def ticket_vm_list(self, node):
        path = f'/api2/json/nodes/{node}/qemu'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()
    #获取虚拟机信息
    def ticket_vm_current(self, node, vmid):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/current'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()
    #启动虚拟机
    def ticket_vm_start(self, node, vmid):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/start'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.post(url=url, headers=headers, verify=False)
        return r.json()
    #关闭虚拟机
    def ticket_vm_stop(self, node, vmid):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/stop'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.post(url=url, headers=headers, verify=False)
        return r.json()
    #创建虚拟机
    def ticket_vm_create(self, node,data):
        path = f'/api2/json/nodes/{node}/qemu/'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.post(url=url, data=data,headers=headers, verify=False)
        return r.json()


if __name__ == '__main__':
    op = Pve_api(ip='192.168.1.1', username='root@pam', password='xxxxxxxxx')
    op.get_ticket()
    data = {
        'vmid': '102',
        'sata0': 'local:100',
        'cores': '2',
        'memory': '1024',
        'name': 'test',
        'cdrom': 'local:iso/debian-11.3.0-amd64-netinst.iso'
    }
    #创建虚拟机的参数,其它参数官网有
    r=op.ticket_vm_create(node='node1',data=data)
    print(r)
  '''
{'data': 'UPID:node1:xxxxxxxxxxxxxxxxx:qmcreate:102:root@pam:'}返回创建成功
  '''

参考文档:
Sam Liu的代码open in new window
PVE官网API说明文档open in new window

流量镜像

少数情况下需要把虚拟机流量镜像到另一个虚拟机
pve下测试失败,暂时保留在哪儿,之后再研究吧 首先安装Open vSwitch

apt install openvswitch-switch

创建一个流量镜像

ovs-vsctl -- --id=@p get port tap7203i3 \
-- --id=@m create mirror name=span1 \
select-all=true output-port=@p \
-- set bridge vmbr11 mirrors=@m

模拟hub直连

可以用于流量回放等测试

操作方式如下:

  1. 创建一个Linux Bridge类型网桥的vmbr3

  2. 进入shell执行

brctl setageing vmbr3 0  #禁用mac老化时间,重启设备失效
  1. 两个虚拟机都使用vmbr3然后关闭防火墙

  2. 使用tcpreplay测试是否生效

  3. 持久化配置(按需配置)

auto vmbr3
iface vmbr3 inet manual
        bridge-ports none
        bridge-stp off
        bridge-fd 0
        #配置老化时间为0
        post-up /sbin/brctl setageing vmbr3 0 || true

命令行修改配置

# --hotplug 1  热拨插,注意mac地址修改为现在的mac地址,否则mac变动可能导致网络不通
qm set 100 --net2 macaddr=B2:69:11:27:22:18,virtio,bridge=vmbr21 --hotplug 1