PHP本身不能直接创建虚拟机,但通过PHP的libvirt扩展调用KVM/QEMU底层接口,就能把PHP脚本变成虚拟机创建与管理工具,本指南覆盖从安装扩展、编写XML配置到启动虚拟机、查询状态的全过程,适合在Linux服务器上做自动化运维或Web管理面板开发。
php怎么创建虚拟机:调用链与前置条件
很多开发者一开始会困惑:PHP是脚本语言,怎么能跟虚拟机这种底层资源打交道?实际上PHP只是负责生成符合libvirt规范的XML配置,再通过扩展把请求发给系统的libvirtd守护进程,由libvirtd调用KVM/QEMU完成真正的硬件虚拟化,整条链路可以理解为:PHP脚本 → php-libvirt扩展 → libvirtd服务 → KVM/QEMU → 虚拟机实例。
这套方案适合几类典型场景:
- 需要批量开出几十台开发测试环境的运维团队
- 想在自建Web后台里点按钮就创建虚拟机的开发人员
- 已经用PHP写过业务系统,不想为了虚拟机管理再引入Python或Go技术栈的团队
你需要准备一台支持硬件虚拟化的Linux服务器,多数情况下x86_64架构的云服务器或物理机都能满足要求,建议优先使用CentOS 8/9、Rocky Linux、Ubuntu 20.04/22.04这类主流发行版,减少扩展编译时的坑。
环境准备:在Linux服务器上用php创建虚拟机的基础依赖
检查CPU虚拟化支持
先确认服务器CPU是否开启了VT-x/AMD-V,命令如下:
egrep -c '(vmx|svm)' /proc/cpuinfo
只要输出结果大于0,就说明硬件虚拟化可用,云服务器如果返回0,可能是底层没有透传虚拟化标志,这种情况无法使用KVM加速,只能改用QEMU纯软件模拟,性能会差很多。
安装KVM与libvirt核心组件
Ubuntu/Debian执行:
apt update
apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst
CentOS/Rocky执行:
dnf install qemu-kvm libvirt libvirt-client virt-install
安装完成后启动libvirtd并设置开机自启:
systemctl enable --now libvirtd
systemctl status libvirtd
编译安装PHP libvirt扩展
这是整个流程里最容易出问题的环节,PHP的libvirt扩展需要从PECL编译,所以先装编译工具和开发头文件:
Ubuntu/Debian:
apt install php-dev php-pear libvirt-dev pkg-config gcc make
CentOS/Rocky:
dnf install php-devel php-pear libvirt-devel gcc make
然后通过PECL安装扩展:
pecl install libvirt
编译完成后,在php.ini中加入一行:
extension=libvirt.so
CLI模式和FPM模式要分别确认加载,可以用以下命令验证:
php -m | grep libvirt
如果没输出,检查php.ini路径,或者用php --ini定位配置文件。
把运行PHP脚本的用户加入libvirt组,否则连接本地系统级hypervisor时会报权限错误:
usermod -aG libvirt www-data # Ubuntu/Debian
usermod -aG libvirt apache # CentOS/Rocky
改完组权限后需要重新登录或重启PHP-FPM才生效。
php调用libvirt创建虚拟机教程:磁盘准备与XML定义
创建虚拟磁盘文件
先准备一块qcow2格式的磁盘,这种格式支持写时复制和快照,适合虚拟机频繁创建销毁的场景:
qemu-img create -f qcow2 -o preallocation=metadata /var/lib/libvirt/images/web01.qcow2 20G
再准备一个系统安装ISO,比如Debian 12或Rocky Linux 9的ISO文件,放到/var/lib/libvirt/images/目录下。
编写PHP连接脚本
新建一个create_vm.php文件,先连接本地libvirtd:
<?php
$conn = libvirt_connect('qemu:///system', false);
if (!is_resource($conn)) {
die('连接libvirtd失败,请检查服务状态和用户组权限');
}
echo "已连接到QEMU/KVMn";
?>
连接地址qemu:///system表示连接本机系统级QEMU,远程主机可以用qemu+ssh://root@192.168.1.100/system,不过生产环境建议配置SSH密钥免密。
组装虚拟机XML配置
PHP创建虚拟机的核心就是把XML字符串传给libvirt,以下是一份可用的基础配置:
$xml = <<<XML
<domain type='kvm'>
<name>web01</name>
<memory unit='KiB'>2097152</memory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='pc-q35-7.2'>hvm</type>
<boot dev='cdrom'/>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/web01.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<disk type='file' device='cdrom'>
<source file='/var/lib/libvirt/images/debian-12.iso'/>
<target dev='sda' bus='sata
'/>
<readonly/>
</disk>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
</interface>
<graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
</devices>
</domain>
XML;
这份XML设置了2GB内存、2个vCPU、一块20G系统盘、一个ISO光驱,以及一张走NAT默认网络的网卡,VNC监听在0.0.0.0上,方便后续用VNC客户端连接安装系统。
定义并启动虚拟机
把XML传入libvirt定义域并启动:
$domain = libvirt_domain_define_xml($conn, $xml);
if (!$domain) {
die('定义虚拟机失败:' . libvirt_get_last_error());
}
if (libvirt_domain_start($domain)) {
echo "虚拟机 web01 已启动n";
} else {
echo "启动失败:" . libvirt_get_last_error() . "n";
}
到这里,PHP脚本已经完成了从磁盘创建到虚拟机启动的完整闭环,之后可以用VNC客户端连接服务器IP的自动分配端口,完成系统安装。
常见报错排查
Failed to connect socket to '/var/run/libvirt/libvirt-sock':libvirtd没启动或当前用户不在libvirt组。unsupported configuration: CPU mode 'custom':核心配置里没有显式指定CPU mode,可以在XML里加<cpu mode='host-passthrough'/>。Permission denied:检查磁盘文件和ISO文件的读取权限,libvirt进程默认以qemu用户运行。
用PHP查询虚拟机状态与资源占用
创建完虚拟机后,通常还需要在Web面板里展示运行状态,PHP libvirt扩展提供了现成的查询函数:
$domains = libvirt_list_domains($conn);
foreach ($domains as $domainName) {
$domain = libvirt_domain_lookup_by_name($conn, $domainName);
$info = libvirt_domain_get_info($domain);
echo "虚拟机:{$domainName}n";
echo "状态:" . ($info['state'] == 1 ? '运行中' : '已关机') . "n";
echo "内存占用:{$info['memory']} KBn";
echo "vCPU数量:{$info['nrVirtCpu']}n";
echo "运行时长:{$info['cpu_time']} nsn";
echo "-----------------n";
}
libvirt_domain_get_info返回数组里,state为1表示运行中,5表示已关机,3表示暂停,这些字段足够支撑一个简易的虚拟机列表页。
php虚拟机管理平台对比:自研脚本还是用现成面板
很多团队会纠结:既然PHP能管理虚拟机,是自己写一套管理平台,还是直接用WebVirtCloud、Kimchi这类现成开源面板?两者在开发成本、灵活性上差异明显。
| 维度 | PHP自研脚本 | 现成面板 |
|---|---|---|
| 开发周期 | 基础功能1-3天,完整平台周期较长 | 部署当天可用 |
| 功能覆盖 | 按需开发,轻量灵活 | 快照、迁移、VNC代理齐全 |
| 技术栈统一 | PHP团队易维护 | 往往引入Python或Node |
| 适合规模 | 10台以内开发测试机 | 几十台以上生产集群 |
| 权限控制 | 自己实现或对接现有系统 | 面板自带用户体系 |
行业共识认为,如果只是内部开发环境或少量测试机,用PHP脚本直接操作libvirt是投入产出比最高的方式,但如果要对外提供虚拟机租用服务,现成面板的认证、隔离、计费模块能省下大量安全审计成本。
至于php虚拟机搭建多少钱,这个成本主要不在PHP代码本身,而在服务器硬件和网络资源,以自用开发环境为例,一台16核32G内存的二手服务器在北京这类机房资源集中的地域,月租成本通常在几百元区间;如果选择云厂商的裸金属实例,价格会随带宽和地域浮动,PHP扩展和KVM软件本身都是开源免费,不产生额外授权费用。
Q&A:php建立虚拟机的常见疑问
PHP 8能用libvirt扩展吗?
可以,但需要编译最新版php-libvirt扩展,部分PECL老版本对PHP 8兼容不好,如果pecl install libvirt失败,去GitHub拉取源码手动编译phpize && ./configure && make && make install能解决多数问题。
用PHP创建虚拟机一定要root权限吗?
不需要root,但运行PHP的用户必须加入libvirt组,如果是FPM模式,要把www-data或apache用户加入libvirt组;如果是CLI模式,把当前登录用户加入即可,加入后需要重新登录或重启服务。
没有KVM硬件虚拟化还能用PHP创建虚拟机吗?
可以,把XML里的<domain type='kvm'>改成<domain type='qemu'>,QEMU会用软件模拟CPU指令,但性能会大幅下降,只适合做功能验证或极轻量任务。
从安装php-libvirt扩展到生成XML定义,再到启动和查询虚拟机,PHP已经能胜任日常虚拟机管理的大部分需求,只要把权限、XML配置和错误处理三个环节打磨好,用PHP建立虚拟机并不比Python或Go方案复杂。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/647565.html





