Incus手册
什么是Incus
2023年7月5日,Canonical宣布全面接管LXD。原先的LXD工作组对此相当不满,因此Fork并重新制作了移除掉所有Canonical相关内容的Incus。
抛开这些历史问题不谈,Incus的本质是:
一套为容器和虚拟机提供统一的集群化管理接口的系统。
架构
Incus由三个部分组成:
- 服务端:即
incusd,提供基于UNIX套接字或REST API的接口供客户端访问。 - 客户端:即
incus,提供访问服务端进行集群管理的功能。 - 镜像仓库:提供容器镜像或虚拟机磁盘的下载仓库,即
https://images.linuxcontainers.org。 
Incus管理的对象包括虚拟机和系统容器(相对于应用容器而言,即LXC),它们的区别如下表:
| 虚拟机 | 系统容器 | 应用容器 | 
|---|---|---|
| 使用独立内核 | 使用宿主机内核 | 使用宿主机内核 | 
| 使用了硬件虚拟化功能(Intel VT-X或AMD-V) | 只使用内核功能 | 只使用内核功能 | 
| 使用资源最多 | 使用资源较少 | 使用资源较少 | 
| 有完整的引导过程,因此启动较慢 | 只有用户空间的Init过程,启动较快 | 完全没有引导和Init过程,启动最快 | 
| 典型代表是Qemu-KVM | 典型代表是LXC | 典型代表是Docker | 

安装
目前Incus服务端仅在Debian 13+的官方源中进行提供:
1  | apt install incus  | 
客户端不限平台,二进制程序可以在Github页面直接下载。
安装Incus后,被添加到incus-admin附加组的用户有权对其进行管理。
初始化
执行:
1  | incus admin init  | 
命令进行初始化,初始化过程包括以下几个问题:
- 是否启用集群模式?默认为否。
- 如果选择是,那么会询问使用的IP、以及是否加入已存在的集群。
 - 如果选择加入已存在的集群,那么会要求提供集群Token。
 - 如果选择不加入,那么会询问新建的集群名称。
 
 - 是否创建一个存储池?默认为是。
- 存储池默认名称为
default。使用dir存储引擎(无法修改)。 
 - 存储池默认名称为
 - 是否自动创建网桥?默认为是。
- 自动创建的网桥是一个三层交换机(路由器)。用户可以手动提供IPv4/IPv6使用的子网,也可以让Incus自动选择一个子网。
 - 如果选择是,还会要求提供网桥的设备名称,默认为
lxcbr0。 - 如果选择否,那么会要求用户选择一个已存在的网桥或网络接口。可以创建一个二层网桥,或是使用一个物理接口,不过如果是物理接口的话,会被Incus占用,不能再被宿主机使用。
 
 - 是否在网络上暴露该服务器(即启用REST API)?默认为否。
 - 是否定期更新镜像?默认为是。
 - 是否打印一个Preseed自动化YAML?默认为否。
 
除了手动初始化,还有三种自动初始化方式:
--minimal:全部使用默认选项,自动化初始化。--auto:从命令行选项获取配置,自动化初始化。可用配置有:--network-address:绑定的IP。--network-port:绑定的端口号,默认为8443。--storage-backend=dir|lvm|btrfs|zfs|ceph:使用的存储引擎。--storage-create-device=/dev/设备:使用device引擎并指定设备存储。--storage-create-loop=大小:使用loop引擎并指定大小。--storage-pool='名称':指定存储池名称。
--preseed:从标准输入获取Preseed YAML配置文件,自动化初始化。
网络
检察网络
列出可用网络:
1  | incus network list  | 
检查网络:
1  | incus network show|info 网络名  | 
创建网络
Incus可以创建一个用于虚拟机/容器的网络:
1  | incus network create 网络名称 [参数=值] --type=bridge|ovn|macvlan|sriov|physical [--target=节点]  | 
bridge:使用一个三层交换机进行路由的网络。ovn:使用OVN网络。macvlan:在网卡上创建MACVLan设备。sriov:使用支持SR-IOV的网卡。physical:直接使用物理网卡,注意这会导致该网卡在宿主机上不可用。
bridge和ovn常用参数有:
ipv4.address:子网的CIDR,默认为auto。ipv4.dhcp:是否启用DHCP,默认为true。ipv6.address:子网的CIDR,默认为auto。ipv6.dhcp:是否启用DHCP,默认为true。
macvlan、sriov和physical参数有:
parent:使用的父网卡。
在集群中创建网络时,需要在每个节点上都执行一次创建命令,最后再不带--target选项执行一次创建命令。
接入网络
执行以下命令将虚拟机/容器实例接入网络:
1  | incus network attach 网络名 实例名 实例中的接口名  | 
实际上这是这条命令的别名:
1  | incus config device add 实例名 实例中的接口名 nic network=网络名  | 
实际上,Incus也支持让实例直接接入接口:
1  | incus config device add 实例名 实例中的接口名 nic nictype=bridged|macvlan|sriov|physical|routed parent=接口名  | 
这种方式不是推荐方式,唯一实用的场景是手动创建一个二层网桥并使用bridged模式让实例接入。
编辑网络
要在创建后修改网络配置,执行:
1  | incus network set 网络名 参数=值  | 
或是执行:
1  | incus network edit 网络名  | 
直接编辑YAML配置。
ACL
Incus支持对网络创建ACL规则。首先创建一个ACL配置:
1  | incus network acl create ACL配置名 [参数=值]  | 
可用参数有:
description:描述。ingress:入站规则列表。egress:出站规则列表。
然后在ACL配置中添加规则:
1  | incus network acl rule add ACL配置名 ingress|egress [参数=值]  | 
可用参数有:
action=allow|reject|drop:必须参数,针对特定数据包的操作。state=enabled|disabled|logged:规则状态。logged表示登记模式。description:描述。source:匹配源地址,可以是CIDR,也可以是IP范围。特殊的值@internal表示内网通信,@external表示外网通信。destination:匹配目标地址,可以是CIDR,也可以是IP范围。protocol=icmp4|icmp6|tcp|udp:网络协议。source_port:仅支持tcp|udp协议,匹配源端口号。destination_port:仅支持tcp|udp协议,匹配目标端口号。icmp_type:仅支持icmp4|icmp6协议,匹配ICMP类型号。icmp_code:仅支持icmp4|icmp6协议,匹配ICMP状态码。
要编辑一个ACL配置,执行:
1  | incus network acl edit ACL配置名  | 
要查看ACL日志,执行:
1  | incus network acl show-log ACL配置名  | 
要分配ACL,执行:
1  | incus network set 网络名 security.acls=ACL配置名  | 
或是仅对实例生效:
1  | incus config device set 实例名 实例中的网络接口 security.acls=ACL配置名  | 
配置了ACL的网络/接口的默认行为是阻止所有的出入站数据包,要修改这一行为,执行:
1  | incus network set 网络名 security.acks.default.ingress|egress.action=allow  | 
或
1  | incus config device set 实例名 实例中的网络接口 security.acls.default.ingress|egress.action=allow  | 
端口映射
Incus可以方便地配置端口映射,先添加监听的IP:
1  | incus network forward create 网络名 监听IP [参数=值]  | 
可用参数有:
description:描述。ports:端口列表。
然后即可添加映射端口:
1  | incus network forward port add 网络名 监听IP tcp|udp 监听端口 目标IP [参数=值]  | 
其他参数如下:
target_port:目标端口,默认和监听端口一致。description:描述。
编辑执行:
1  | incus network forward edit 网络名 监听IP  | 
存储
Incus将存储使用池式管理。支持以下几类存储引擎:
| 存储特性 | 目录 | BTRFS | LVM | ZFS | CEPH RBD | CEPHFS | CEPH OBJ | 
|---|---|---|---|---|---|---|---|
| 宿主机共享 | 是 | 是 | 否 | 是 | 否 | 否 | 否 | 
| 独立磁盘 | 否 | 是 | 是 | 是 | 否 | 否 | 否 | 
| 回环设备 | 否 | 是 | 是 | 是 | 是 | 否 | 否 | 
| 远程存储 | 否 | 否 | 否 | 否 | 是 | 是 | 是 | 
| 写入优化 | 否 | 是 | 是 | 是 | 是 | 否 | 否 | 
| 克隆 | 否 | 是 | 是 | 是 | 是 | 是 | 否 | 
| 快照 | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 
| 配额 | 是(Ext4或Xfs) | 是 | 是 | 是 | 是 | 是 | 是 | 
检察存储池
列出可用存储池:
1  | incus storage list  | 
检查存储池:
1  | incus storage show|info 池名  | 
创建存储池
执行:
1  | incus storage create 池名 存储引擎 [参数=值]  | 
dir引擎可用参数有:
source=目录位置:指定目录位置。
btrfs引擎可用参数有:
size=:大小。source=/dev/sdX:指定建立了Btrfs文件系统的块设备。
lvm引擎可用参数有:
size=:大小。source=/dev/sdX lvm.vg_name=VG名:在指定块设备上创建VG并使用。source=VG名:指定使用的VG。lvm.thinpool_name=:创建一个指定名称的Thinpool。
zfs引擎可用参数有:
size=:大小。source=/dev/sdX zfs.pool_name=ZPool名:在指定块设备上创建ZPool并使用。source=ZPool名:指定使用的ZPool。source=ZPool名/Dataset名 volume.zfs.block.mode=yes:指定使用的Dataset。
ceph(Ceph RBD)可用的参数有:
ceph.cluster_name=:使用的Ceph集群名。ceph.osd.pool_name=:使用的Ceph池名。source=OSD名:使用现有的Ceph OSD池。
cephfs引擎可用参数有:
source=文件系统名[/目录]:指定使用的CephFS文件系统。cephfs.create_missing=true:自动创建不存在的目录。
cephobject引擎可用参数有:
cephobject.radosgw.endpoint=:指定Ceph Object的HTTP入点。
在集群中创建存储池时,需要在每个节点上都执行一次创建命令,最后再不带--target选项执行一次创建命令。
编辑存储池
要在创建后修改存储池配置,执行:
1  | incus storage set 池名 参数=值  | 
例如:
1  | incus storage set 池名 size=大小  | 
或是执行:
1  | incus storage edit 池名  | 
直接编辑YAML配置。
使用存储池
很简单,在启动实例时使用--storage=池名选项指定即可。如果没有指定,那么使用当前的Profile的配置。
要移动实例,执行:
1  | incus move 实例名 --storage 池名  | 
创建存储卷
Incus在创建实例时会自动创建所需的卷,在移除实例时会自动删除,因此一般情况下,存储卷不需要手动创建,创建的命令为:
1  | incus storage volume create 池名 卷名 [--type=filesystem|block] [参数=值]  | 
可用类型有两种:
filesystem:存储容器和容器镜像。不能挂载在虚拟机中。block:存储虚拟机的虚拟磁盘。不能挂载在容器中。
可用参数有:
size:大小。
此外,还有一种特殊的类型iso,也就是可挂载的ISO镜像卷,不过这种卷的创建方式是:
1  | incus storage volume import 池名 ISO路径 卷名 --type=iso  | 
这种卷只能是只读的。
要设置卷的用途(备份或镜像),执行:
1  | incus config set storage.backups_volme|storage.images_volume 池名/卷名  | 
查看存储卷:
1  | incus storage volume list 池名  | 
设置存储卷
要在创建后修改存储卷配置,执行:
1  | incus storage set 池名 卷名 参数=值  | 
例如:
1  | incus storage set 池名 卷名 size=大小  | 
或是执行:
1  | incus storage edit 池名 卷名  | 
直接编辑YAML配置。
挂载存储卷
对于filesystem卷:
1  | incus storage volume attach 池名 卷名 容器实例名 挂载路径  | 
对于block卷:
1  | incus storage volume attach 池名 卷名 虚拟机实例名  | 
此外,也可以把卷作为一个设备挂载:
1  | incus storage volume attach 池名 卷名 实例名 设备名 [挂载路径] [参数=值]  | 
这条命令实际上是个别名:
1  | incus config device add 实例名 设备名 disk pool=池名 source=卷名 [path=路径] [参数=值]  | 
设置IO限制
在把卷作为设备挂载时,可以通过参数设置IO限制,在本质上,这是通过Cgroup实现的:
boot.priority:设备的引导优先级,用于虚拟机。io.bus=nvme|virtio-blk|virtio-scsi:设备的接口。io.cache=none|writeback|unsafe:设备的写入缓存。limits.max:最大读写速度限制。limits.read:最大读速度限制。limits.write:最大写入速度限制。
拷贝/移动存储卷
也就是:
1  | incus storage volume copy|move 池名/卷名 池名/卷名  | 
不过,要在集群节点之间移动的话,还要加上:
1  | incus storage volume copy|move 池名/卷名 池名/卷名 --target 节点 --destination-target 节点  | 
还可以在Incus集群间移动:
1  | incus storage volume copy|move 主机名:池名/卷名 主机名:池名/卷名  | 
备份卷
创建一个快照:
1  | incus storage volume snapshot 池名 卷名 [快照名]  | 
检查快照:
1  | incus storage volume show|info 池名 卷名  | 
编辑快照:
1  | incus storage volume edit 池名 卷名/快照名  | 
删除快照:
1  | incus storage volume delete 池名 卷名/快照名  | 
还可以设置定时快照:
1  | incus storage volume set 池名 卷名 snapshots.schedule '分 时 日 月 年'|@daily  | 
恢复快照:
1  | incus storage volume restore 池名 卷名 快照名  | 
还可以从快照构建一个新的卷:
1  | incus storage volume copy 池名/卷名/快照名 池名/卷名/快照名  | 
导出备份:
1  | incus storage volume export 池名 卷名 [文件路径]  | 
可用选项如下:
--compression=gzip|bzip2|none:压缩方式。--optimized-storage:仅用于zfs和btrfs,启用优化存储方式。--volume-only:仅备份卷,不备份快照。
恢复备份:
1  | incus storage volume import 池名 文件路径 [卷名]  | 
REST API
Incus支持使用REST API的方式进行远程使用。在服务端上执行:
1  | incus config set core.https_address :8443|IP|URL  | 
以设置REST API监听地址。然后在客户端执行:
1  | incus remote add 名称 IP|URL  | 
以添加,再执行:
1  | incus remote switch 名称  | 
表明当前使用。
客户端和服务端之间可以使用证书认证:
1  | incus config add-certificate 文件路径 --protocol=incus  | 
还可以使用PKI模式,具体步骤为:
- 把CA证书上传到服务端的
/var/lib/incus目录。 - 把CA证书上传到客户端的
~/.config/incus目录。 - 把CA签名的证书上传到客户端和服务端。
 - 重启服务端。
 
集群
Incus支持以集群方式运作,集群内部使用CowSQL分布式数据库存储元信息,并且使用木筏算法选举。集群最少需要三个节点以实现高可用。
查看集群信息:
1  | incus query /1.0/cluster  | 
原理
Incus集群中的每个节点要么是Voter节点,要么是Stand-by节点。Voter节点会参与分布式数据库选主,默认情况下,一个集群中只有三个节点是Voter,其他都是Standby节点。当有一个Voter节点离线时,一个Standby节点会立刻升级为Voter节点并顶替。这些相关配置项分别有:
cluster.max_voters:最大Voter节点数。cluster.max_standby:最大Standby节点数。cluster.offline_threshold:认为离线的响应延迟。
建立集群
在第一台Incus服务器上执行:
1  | incus admin init  | 
然后在:
1  | Would you like to use Incus clustering?  | 
选择yes,设置该服务器的IP即可。这个IP之后可以执行:
1  | incus config set cluster.https_adddress=IP|URL  | 
进行重设。
完成后执行:
1  | incus cluster list  | 
即可检查集群情况。
加入集群
在集群服务器上执行:
1  | incus cluster add 成员名  | 
然后在新的服务器上执行:
1  | incus admin init  | 
然后在:
1  | Would you like to use Incus clustering?  | 
选择yes,在:
1  | Are you joining an existing cluster?  | 
也选择yes,加入集群并输入Token即可。
执行:
1  | incus cluster show|info 节点名  | 
以查看信息。
节点证书位于/var/lib/incus/cluster.crt。
节点组
一部分节点可以组成节点组方便管理,执行:
1  | incus cluster group create 组名  | 
以创建节点组。
设置节点所在组:
1  | incus cluster group assign 节点名 default,组名  | 
该命令会覆盖默认组,所以可以带上default防止覆盖。
将节点添加组:
1  | incus cluster group add 节点名 组名  | 
节点组可以在--target选项中使用@组名调用。
镜像存储
默认情况下Incus会在每个节点上保存一份镜像的拷贝,这一行为可以通过:
cluster.image_minimal_replica:镜像最小副本数,设为-1表示节点数。
修改。
实例存储
新建实例时,Incus默认会尝试保存在当前实例数量最少的那个节点上。不过,也可以使用--target选项指定节点。scheduler.instance可以修改默认操作。
- 如果
scheduler.instance=all,那么使用默认逻辑。 - 如果
scheduler.instance=manual,那么该节点必须被手动指定使用。 - 如果
scheduler.instance=group,那么该节点在用户选择同组节点时可能会被使用。 
执行:
1  | incus cluster set 节点名 scheduler.instance all|manual|group  | 
以设置。
要移动实例,执行:
1  | incus move 实例名 --target 节点名  | 
排空/隔离
有时候我们会希望排空/隔离一个节点(比如升级),此时执行:
1  | incus cluster evacuate 节点名  | 
即可,要恢复,执行:
1  | incus cluster restore 节点名  | 
此外,对于离线节点还可以自动排空,只需要设置:
1  | incus cluster set 节点名 cluster.healing_threshold=秒数  | 
删除节点
1  | incus cluster remove 节点名 [--force]  | 
--force用于移除离线节点。
灾难恢复
有时候你会非常不幸的同时损失多个节点,此时Incus集群会处于不可用状态,要恢复,执行:
1  | incus admin cluster list-database  | 
查看可用的节点。连接一个节点,执行:
1  | systemctl stop incus.service incus.socket  | 
停止服务,然后执行:
1  | incus admin cluster recover-from-quorum-loss  | 
恢复数据。最后再启动服务。
重设IP
当集群中有节点IP发生变化时,必须执行:
1  | incus admin cluster edit  | 
重新设置。
镜像
配置镜像源
Incus会从https://images.linuxcontainers.org拉取镜像,不过这一配置可以进行修改:
1  | incus remote set-url images https://xxx  | 
或者添加:
1  | incus remote add 名称 https://xxx --protocol=simplestreams --public  | 
需要注意的是,Incus只接受HTTPS。
查看远程源中的镜像:
1  | incus image list 源名称:[镜像名] [版本号] [architecture=架构]  | 
镜像默认会自动更新,要禁用这一行为,执行:
1  | incus config set images.auto_update_interval=0  | 
下载镜像
在Incus中,本地镜像实际上也是一个源,名为local:,因此要“下载镜像”实际上就是把镜像拷贝到local:源:
1  | incus image copy 源名称:镜像名/版本 local: [--vm] [--alias=名称] [--copy-aliases] [--auto-update]  | 
如果没有使用--alias或是--copy-alias选项,那么镜像将没有名称,只能使用ID(指纹)指定,很麻烦。
检查镜像信息:
1  | incus image show|info 镜像名|ID  | 
给镜像设置别名:
1  | incus image alias list|create|delete 别名 镜像ID  | 
重设别名:
1  | incus image alias rename 别名 新别名  | 
导出与导入镜像
导出镜像,即把镜像到出到文件中:
1  | incus image export 源名:镜像名 [目录] [--vm]  | 
从文件中导入镜像:
1  | incus image import 镜像文件路径  | 
1  | incus image import 源数据Tar包路径 根文件系统Tar包路径  | 
从实例或快照中发布镜像:
1  | incus publish 实例名[/快照名] [源名:]  | 
镜像Profile
从镜像创建实例时,会自动按顺序使用Profile,这些Profile可以执行:
1  | incus image edit 镜像名  | 
进行修改。
实例
实例,即一个VM或容器,是Incus的中心。Incus使用一致的接口创建VM和容器,但是底层技术是不一样的:
- 容器使用
liblxc实现。 - 虚拟机使用
qemu-kvm实现,附带一个incus-agent虚拟机代理辅助工作。 
创建实例
创建一个实例的命令为:
1  | incus create|launch|init [镜像服务器:]镜像名 实例名 [--vm] [其他选项]  | 
如果没有指定镜像服务器,那么默认使用local:,即本地镜像。
可用的其他选项包括:
-e|--ephemeral:临时模式,停止容器时抹除任何操作。-p|--profile 配置名:指定使用的配置组。--no-profile:不适应任何配置组。这意味着必须手动配置容器。
-c|--config 配置=值:手动设置配置项。-n|--network 网络名:指定使用的Incus网络。-s|--storage 池名:指定使用的Incus存储池。--target 节点:指定使用的集群节点。-d|--device 设备,配置=值:指定一些虚拟设备配置。例如设置根文件系统大小--device root,size=。--empty:什么也不做,新建一个空实例。
要从ISO引导VM,首先需要创建一个ISO镜像的存储卷:
1  | incus storage volume import 池名 ISO文件路径 卷名 --type=iso  | 
然后在虚拟机中添加设备:
1  | incus config device add 实例名 设备名 disk pool=池名 source=卷名 boot.priority=0  | 
安装完成后移除卷:
1  | incus storage volume detach 池名 卷名 实例名  | 
控制与检查实例
所有的Incus实例接口都支持命令行和REST两种方式。
列出实例:
1  | incus list [匹配词=值]  | 
可用匹配词包括:
type=container|vm:类型。status=running|stopped:状态。location=节点名:所在节点。系统类型.*:系统类型。
查看实例信息:
1  | incus info 实例名 [--show-log]  | 
启动实例:
1  | incus start 实例名 [--console]  | 
停止实例:
1  | incus stop 实例名  | 
删除实例:
1  | incus delete 实例名  | 
重建实例(保留配置,删除并重新创建):
1  | incus rebuild [镜像名] 实例名 [--empty]  | 
无特权容器
Incus默认以无特权方式运行容器,因此必须确保Root用户有合适的SubUID和SubGID。SubUID和SubGID的范围中至少要有65536个值,否则启动容器时会立刻失败。
默认情况下,在安装Incus时,会给Root用户创建1000000-1000000000的SubUID和SubGID,这在一般情况下足够了。
在创建容器时,Incus会随机抽取一段UID(以下文字中省略GID)并对容器中的UID进行映射,因为抽取的UID是随机的,所以不同的容器映射的目标UID有可能重合,这在一般情况下没什么问题,不过如果用户对安全性很敏感,可以给容器设置配置项security.idmap.isolated=true,这可以确保容器映射的目标UID是唯一的。
此外,用户也可以手动设置UID映射,只需要给容器设置以下两个配置项:
security.idmap.base:映射的目标UID起点。security.idmap.size:映射的UID数量。
如果用户不希望使用无特权容器(例如嵌套容器环境下),那么可以通过给容器或Profile中设置该配置项关闭:
security.privileged=true
配置实例
查看实例配置,执行:
1  | incus config show 实例名 [--expanded]  | 
配置实例的命令为:
1  | incus config set 实例名 配置项=值  | 
可用的配置项包括:
boot.autostart:随incusd守护进程启动。limits.cpu:可用的CPU。limits.cpu.priority:CPU占用优先级。limits.disk.priority:IO优先级。limits.memory:内存使用数,默认为1GiB。limits.memory.enforce=soft|hard:内存限制性质。limits.memory.swap:可用的交换空间数。security.protection.delete:禁止实例被删除。默认禁用。security.guestapi:是否在实例内提供/dev/incus接口。默认启用。
用于容器的增强功能:
security.privileged:是否运行特权容器,默认禁用。security.idmap.base:用于非特权容器,ID映射的起点。默认为0,表示随机选择。security.idmap.size:用于非特权容器,ID映射的数量。security.idmap.isolated:用于非特权容器,ID映射是否严格独立。默认禁用。security.nesting:是否允许容器嵌套,默认禁用。security.protection.shift:禁止容器ID映射被调整,默认禁用。
用于虚拟机的增强功能:
security.agent.metrics:是否启用指标采集。默认启用。security.csm:是否启用Legacy BIOS支持,默认禁用。security.secureboot:是否启用安全引导,默认启用。security.sev:是否启用AMD安全虚拟化技术。默认禁用。security.sev.policy.es:是否启用AMD安全虚拟化加密。默认禁用。
要给实例添加设备,执行:
1  | incus config device add 实例名 设备名 设备类型 [设备选项=值]  | 
可用的设备类型及其选项有:
nic:网络接口。network=:实际使用的Incus网络。nictype=:直接接入的网络接口类型,不太常用。
disk:磁盘。pool=:使用的存储池。使用source=指定池名。source=:宿主机上的目录映射。source=ceph:池名/卷名 ceph.user_name=用户名 ceph.cluster_name=集群名:使用Ceph RBD。source=cephfs:FS名/路径 ceph.user_name=用户名 ceph.cluster_name=集群名:使用Ceph FS。source=ISO文件路径:使用ISO镜像。boot.priority:设备的引导优先级,用于虚拟机。io.bus=nvme|virtio-blk|virtio-scsi:设备的接口。io.cache=none|writeback|unsafe:设备的写入缓存。limits.max:最大读写速度限制。limits.read:最大读速度限制。limits.write:最大写入速度限制。
unix-char:字符设备。source:设备路径。path:容器内的位置。uid:所属的用户。gid:所属的用户组。mode:权限位,默认为0660。required:是否必要。
unix-block:块设备。source:设备路径。path:容器内的位置。uid:所属的用户。gid:所属的用户组。mode:权限位,默认为0660。required:是否必要。
unix-hotplug:热插拔设备。uid:所属的用户。gid:所属的用户组。mode:权限位,默认为0660。required:是否必要。productid:设备ID。vendorid:设备制造商ID。
usb:USB设备。uid:所属的用户。gid:所属的用户组。mode:权限位,默认为0660。required:是否必要。productid:USB设备ID。vendorid:USB制造商ID。
gpu:GPU设备。gputype=physical:物理显卡直通,可用于容器。id:设备DRM ID。pci:设备PCI地址。productid:设备ID。vendorid:设备制造商ID。uid:所属的用户。gid:所属的用户组。mode:权限位,默认为0660。
gputype=mdev:虚拟机的虚拟显卡。id:设备DRM ID。mdev:使用的虚拟显卡类型。pci:设备PCI地址。productid:设备ID。vendorid:设备制造商ID。
gputype=mig:用于容器的NVIDIA MIG单元。id:设备DRM ID。mig.ci:MIG的计算实例ID。mig.gi:MIG的GPU实例ID。mig.uuid:MIG的设备UUID。pci:设备PCI地址。productid:设备ID。vendorid:设备制造商ID。
gputype=sriov:用于虚拟机的SRIOV。id:设备DRM ID。pci:设备PCI地址。productid:设备ID。vendorid:设备制造商ID。
infiniband:IB网卡。nictype=physical:物理的IB网卡。parent:父网卡。hwaddr:MAC地址。mtu:MTU。name:名称。
nictype=sriov:SRIOV分配的网卡。parent:父网卡。hwaddr:MAC地址。mtu:MTU。name:名称。
tpm:TPM。path:路径,一般为/dev/tpmX。pathrm:资源管理器路径,一般为/dev/tpmrmX。
pci:PCI设备。address:PCI地址。
编辑实例配置:
1  | incus config edit 实例名  | 
快照与备份
快照的实际实现原理随着存储引擎而变化,有些支持CoW的存储引擎支持优化的快照实现方式:
1  | incus snapshot create 实例名 [快照名] [--reuse]  | 
--reuse:覆盖原先已存在的快照。--stateful:保存VM当前的运行状态。
删除快照:
1  | incus delete 实例名/快照名  | 
查看快照信息:
1  | incus info 实例名/快照名  | 
查看快照配置:
1  | incus config show 实例名/快照名  | 
编辑快照配置:
1  | incus config edit 实例名/快照名  | 
还可以设置定时快照:
1  | incus snapshot set 实例名 snapshots.schedule 'Cron日程'|@daily  | 
恢复快照:
1  | incus snapshot restore 实例名 快照名  | 
导出实例:
1  | incus export 实例名 [文件路径]  | 
--compression=gzip|bzip2|none:压缩方式。--optimized-storage:仅用于zfs和btrfs,启用优化存储方式。--instance-only:仅备份实例,不备份快照。
从文件恢复实例:
1  | incus import 文件路径 [实例名]  | 
配置组(Profile)
配置组保存了一系列的实例配置,它可以用于创建实例时复用。不过在创建实例时,命令行选项总是会覆盖配置组中的选项。Incus初始化时,会创建一个默认Profile,名为default。
列出可用配置组:
1  | incus profile list  | 
查看配置组:
1  | incus profile show 配置名  | 
创建一个配置组:
1  | incus profile create 配置名  | 
编辑配置组可以使用配置实例一样的方式:
1  | incus profile set 配置名 配置=值  | 
不过,更合理的方法是直接编辑:
1  | incus profile edit 配置名  | 
在创建实例时可以使用一个配置组:
1  | incus launch 镜像名 实例名 --profile 配置名  | 
也可以给已创建的实例添加配置:
1  | incus profile add|remove 实例名 配置名  | 
执行命令
在实例中执行一条命令:
1  | incus exec 实例名 -- 命令  | 
- 和Docker不一样,Incus不需要手动分配伪终端,它有能力在需要的情况下(运行Shell)自动分配。不过,如果希望强制使用非交互模式,也是可以的,只需要添加
--force-noninteractive选项。 - 默认情况下,Incus使用
root用户和组运行命令,工作目录为/root,这些行为可以通过--user、--group和--cwd选项修改。 - 使用
--env ENV=VALUE选项设置环境变量。 
要持久化设置环境变量,执行:
1  | incus config set 实例名 environment.ENV=VALUE  | 
进入终端
Incus可以连接到实例的/dev/console设备上以获取交互式终端:
1  | incus console 实例名 [--show-log]  | 
对于虚拟机,尤其是没有安装incus-agent的虚拟机,可以使用对Agent没有要求的SPICE协议进行连接,不过,这需要系统上安装virt-viewer:
1  | incus console 实例名 --type=vga  | 
创建实例时可以自动进入终端:
1  | incus init 镜像名 实例名 --console  | 
获取实例中文件
Incus通过一些手段,实现了直接编辑实例中的文件:
1  | incus file edit 实例名/文件路径  | 
注意,你不能用这种方式创建文件。
也可以删除实例中的文件:
1  | incus file delete 实例名/文件路径  | 
还可以获取实例中的文件到宿主机:
1  | incus file pull [-r] 实例名/文件路径 宿主机文件路径  | 
- 如果宿主机文件路径是
-,那么会直接打印文件内容(拷贝到标准输出)。 -r表示递归拷贝。
上传宿主机文件:
1  | incus file push [-r] 宿主机文件路径 实例名/文件路径  | 
映射宿主机目录:
1  | incus file mount 实例名/路径 宿主机路径  | 
配置SFTP服务器:
1  | incus file mount 实例名 [--listen 地址:端口]  | 
- 默认情况下,地址为
127.0.0.1,端口号随机生成。 
这样就可以使用sshfs连接了:
1  | sshfs 用户名@地址:/路径 本地路径 -p 端口号  | 
迁移
实例可以在节点间迁移。执行:
1  | incus copy 实例名 目标主机:实例名  | 
项目(Project)
项目是一组相互关联的实例的合集。项目可以包含一系列的镜像、网络和存储。
Incus初始化时会附带一个default项目。
创建项目
1  | incus project create 项目名 --config 配置项=值  | 
查看项目:
1  | incus project list  | 
配置项目
1  | incus project set 项目名 配置项=值  | 
可用配置项有:
features.images:是否允许存储镜像。features.networks:是否允许存储网络。features.storage.buckets:是否允许Bucket存储。features.storage.volumes:是否允许存储卷。features.profiles:是否允许存储Profile。limits.containers:容器数量。limits.virtual-machines:VM数量。limits.instances:实例数量。limits.cpu:CPU限制。limits.memory:内存限制。limits.disk:存储限制。limits.networks:网络限制。limits.processes:进程限制。restricted:是否启用限制。restricted.backups:限制使用备份。restricted.containers.privilege:限制使用特权容器。restricted.containers.nesting:限制容器嵌套。
编辑项目配置:
1  | incus project edit 项目名  | 
切换项目
配置完成后,可以切换项目:
1  | incus project switch 项目名  | 
或者,可以在Project间移动实例:
1  | incus move 实例名 新实例名 --project 项目名 --target-project 项目名  | 
用户特定项目
要将项目绑定到一个用户,执行:
1  | incus config trust add --projects 项目名 --restricted  | 
1  | incus config trust add-certificate 证书路径 --projects 项目名 --restricted  |