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 |