Ubuntu LXD

LXD 安装

Ubuntu 20 已缺省安装好 Snap,LXD 版本为 4.0.9,Ubuntu 16 18 需自行安装。

Ubuntu 16 / 18 安装 LXD,建议先安装 Snap,再以 Snap 安装指定的 LXD 版本。

先更新 ubuntu:
sudo apt-get update && sudo apt-get upgrade -y

再安装 snap:
sudo apt install snapd -y

再来决定要安装 LXD 的版本

snap info lxd

可以看到有那些 channels 可供安装
channels:
  latest/stable:    5.8-bb9c9b1   2022-11-25 (23983) 143MB -
  latest/candidate: 5.8-bb9c9b1   2022-11-22 (23983) 143MB -
  latest/beta:      ↑
  latest/edge:      git-38127b4   2022-12-06 (24066) 143MB -
  ...
安装 4.0 稳定版:
sudo snap install lxd --channel=4.0/stable

检查安装的版本:
lxd version

4.0.9

安装最新的稳定版:
sudo snap install lxd --channel=latest/stable

Ubuntu 16 (非以 Snap) 安装 LXD
sudo apt install lxd -y

检查安装的版本:
lxd --version

2.0.11
Ubuntu 18 (非以 Snap) 安装 LXD
sudo apt install lxd -y

检查安装的版本:
lxd version

3.0.3

非以 Snap 安装 LXD 后,要切换为 Snap 的环境可参阅 更新(迁移) LXD 版本

将非 root 帐户加入到 lxd 群组

目前用户 (除了 root) 需加入 lxd 群组,才能操作 LXD。

安装后 lxd 群组应该存在。

$ cat /etc/group | grep lxd
lxd:x:116:user

可以看一下目前用户是否在 lxd 群组之内,如果有则不用加入。

先检查一下 lxc list 是否能正确运行:
sudo lxc list

目前用户未加入 lxd 群组 应该出错:
lxc list

Error: Get "http://unix.socket/1.0": dial unix /var/snap/lxd/common/lxd/unix.socket: connect: permission denied
错误消息语意不清,以为是 socket 配置出错。

将目前用户加入 lxd 群组 (非 root 才需要加入):
sudo usermod -a -G lxd $(whoami)
newgrp lxd

应该能正确运行:
lxc list

LXD 初始化

sudo lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
是否使用集群
Do you want to configure a new storage pool? (yes/no) [default=yes]:
是否要配置新的保存池

Name of the new storage pool [default=default]:
新保存池的名称

Name of the storage backend to use (ceph, btrfs, dir, lvm, zfs) [default=zfs]:
要使用保存后端的类型

Create a new ZFS pool? (yes/no) [default=yes]:
创建一个新的 ZFS 池

Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:

Size in GB of the new loop device (1GB minimum) [default=30GB]:
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
是否在本机创建一个名为 lxdbr0 的 NAT 桥接网卡

What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
lxdbr0 是否使用 IPv4 地址

What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
lxdbr0 是否使用 IPv6 地址
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
不自动创建本机桥接网卡

Would you like to configure LXD to use an existing bridge or host interface? (yes/no) [default=no]: yes
你想将 LXD 配置为使用现有的桥接网卡吗? 是的

Name of the existing bridge or host interface: br0
现有桥接网卡名称 br0
Would you like the LXD server to be available over the network? (yes/no) [default=no]:
是否 (现在) 启动 LXD 服务器,如远程拷贝。
Would you like the LXD server to be available over the network? (yes/no) [default=no]: yes
现在启动 LXD 服务器

Address to bind LXD to (not including port) [default=all]:
Port to bind LXD to [default=8443]:

Trust password for new clients:
输入远程用户连接密码

Again:
再输入一次
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
是否自动更新影像档缓存

Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

LXD 创建容器

列示影像档:
lxc image list images: ubuntu -c ld (1)

list images 结果:
+-------------------------------------+-----------------------------------------+
|                ALIAS                |               DESCRIPTION               |
+-------------------------------------+-----------------------------------------+
| ubuntu/16.04 (7 more)               | Ubuntu xenial amd64 (20230118_07:42)    |
+-------------------------------------+-----------------------------------------+
| ubuntu/18.04 (7 more)               | Ubuntu bionic amd64 (20230118_07:42)    |
+-------------------------------------+-----------------------------------------+
| ubuntu/22.10 (7 more)               | Ubuntu kinetic amd64 (20230118_07:42)   |
+-------------------------------------+-----------------------------------------+
| ubuntu/focal (7 more)               | Ubuntu focal amd64 (20230118_07:43)     |
+-------------------------------------+-----------------------------------------+
1 -c ld 参阅 lxc image list images -h
Flags:
  -c, --columns   Columns (default "lfpdasu")

缺省格式为 lfpdasu,如下对应
l:ALIAS
f:FINGERPRINT
p:PUBLIC
d:DESCRIPTION
a:ARCH
s:SIZE
u:UPLOAD DATE

得知 Image ALIAS Name: ubuntu/18.04,实际上的影像文件名称为 ubuntu:18.04 可以使用代号 ubuntu:bionic (代号参阅: Releases - Ubuntu Wiki ),不过就算把影像档输入 ubuntu/18.04 它会自动修正。

由影像档创建 (初始化) c1 容器:
lxc init ubuntu/18.04 c1

Creating c1
The local image 'ubuntu/18.04' couldn't be found, trying 'ubuntu:18.04' instead.

LXD 会自动出找出正确的影像档。
第一次会自动下载影像档,第二次则会使用已下载的影像档。

lxc init 换成 lxc launch,所有的参数都是相同的,唯一的差别在于创建容器后会自动启动。

由影像档创建 c1 容器后自动启动:
lxc launch ubuntu:18.04 c1
显示容器列表:
lxc list

+------+---------+------+------+------------+-----------+
| NAME |  STATE  | IPV4 | IPV6 |    TYPE    | SnapSHOTS |
+------+---------+------+------+------------+-----------+
| c1   | STOPPED |      |      | PERSISTENT | 0         |
+------+---------+------+------+------------+-----------+

启动 c1 容器:
lxc start c1

显示容器列表:
lxc list -c ns4 (1)

lxc list 结果:
+------+---------+----------------------+
| NAME |  STATE  |         IPV4         |
+------+---------+----------------------+
| c1   | RUNNING | 10.43.172.214 (eth0) |
+------+---------+----------------------+
1 ns4 参阅 lxc list -h
Flags:
  -c, --columns   Columns (default "ns46tSL")
      --fast      Fast mode (same as --columns=nsacPt)

LXD 桥接 br0 网卡

LXD 在缺省的情况下使用 NAT 的方式,容器只能被 Host 访问,如果其他主机要能访问,必须使用 Host 的桥接网卡。

查找主机是否使用 br0 桥接网卡:
ip route show default

default via 192.168.1.254 dev br0 proto dhcp src 192.168.1.31 metric 100

将容器的网络桥接至 br0,以 profile pf-br0 来实现。

创建 pf-br0 profile:
lxc profile create pf-br0
lxc profile device add pf-br0 eth0 nic nictype=bridged parent=br0 name=eth0

显示 pf-br0 的内容:
lxc profile show pf-br0

config: {}
description: ""
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br0
    type: nic
name: pf-br0
used_by: []

创建一个新容器 c2 profile 为 defaultpf-br0:

lxc launch ubuntu:18.04 c2 --profile default --profile pf-br0
显示容器列表:
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 10.43.172.214 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+

现有容器 c1 的 profile 为 default 加入 pf-br0

lxc profile add c1 pf-br0
lxc profile assign c1 default,pf-br0

上述为等效指令,上方为加入,下方 (全) 指定。

显示容器列表:
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+

容器 c1 删除 profile pf-br0

lxc profile remove c1 pf-br0
lxc profile assign c1 default

上述为等效指令,上方为移除,下方 (全) 指定。

修改 profile default 桥接至 br0

列出 default 的组态:
lxc profile show default

devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: lxdbr0
    type: nic
将 default 的 parent 的 lxdbr0 修改成 br0
lxc profile device set default eth0 parent br0
列出 default 的组态:
lxc profile show default

devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br0
    type: nic
显示容器列表:
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+

Ubuntu 20 在缺省安装的 Snap LXD 4.0.9,将 parent 修改成 br0 时出错。

运行同样的指令:
lxc profile device set default eth0 parent br0

Error: Device validation failed for "eth0": Cannot use "nictype" property in conjunction with "network" property
显示 profile default:
lxc profile show default

devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic

缺少 nictype: bridged
default (profile) 移除 eth0 设备:
lxc profile device remove default eth0

default (profile) 加入完整的 eth0 设备描述:
lxc profile device add default eth0 nic nictype=bridged parent=br0 name=eth0

容器设置设备

建议不要在容器设置设备,应使用 profile,在维护时才不会混淆。

在运行之前先检查一下 c1 组态:
lxc config show c1

...
devices: {}
...

容器设置设备有多种方式

lxc config device add 语法:
lxc config device add -h

lxc config device add [<remote>:]<container|profile> <device> <type> [key=value...] [flags]

将容器 c1 设置为 lxdbr0 网卡:
lxc config device add c1 eth0 nic nictype=bridged parent=lxdbr0 name=eth0
lxc network attach 语法:
lxc network attach -h

lxc network attach [<remote>:]<network> <container> [<device name>] [<interface name>] [flags]

将容器 c1 设置为 lxdbr0 网卡:
lxc network attach lxdbr0 c1 eth0 eth0 (1)
1 第一个 eth0 是 device name,第二个 eth0 是 interface name
显示 c1 组态:
lxc config show c1

devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: lxdbr0
    type: nic
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 10.43.172.214 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+

容器移除设备

lxc config device remove c1 eth0
lxc network detach lxdbr0 c1

上述为等效指令

lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+

测试容器设备错误

lxc config device add c1 eth0 nic nictype=bridged parent=lxdbr0 (1)
lxc network attach lxdbr0 c1 eth0 (2)
1 缺少 name=eth0
2 少一个 eth0
显示 c1 组态:
lxc config show c1

devices:
  eth0:
    nictype: bridged
    parent: lxdbr0
    type: nic

当 devices 的 eth0 缺少 name 的描述时,容器将无 IP 位置。

lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING |                      | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
|      |         |                      | pf-br0   |
+------+---------+----------------------+----------+
补上 name 的描述:
lxc config device set c1 eth0 name eth0

容器正常运行(不再示例 lxc list)

一律使用 default (profile) 并移除容器设备

lxc config device remove c1 eth0
lxc config device remove c2 eth0
lxc profile assign c1 default
lxc profile assign c2 default

确定 profile 列表无 pf-br0:
lxc profile list

+---------+---------+
|  NAME   | USED BY |
+---------+---------+
| default | 2       |
+---------+---------+

删除 pf-br0 profile:
lxc profile delete pf-br0
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
+------+---------+----------------------+----------+
显示 profile default:
lxc profile show default

config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by:
- /1.0/instances/c1
- /1.0/instances/c2
显示 br0 网卡:
lxc network show br0

config: {}
description: ""
name: br0
type: bridge
used_by:
- /1.0/instances/c1
- /1.0/instances/c2
- /1.0/profiles/default
managed: false
status: ""
locations: []

容器固定(静态) IP

不知道如何以 LXD 的组态来配置,以下是以单一个容器设置静态 IP 的步骤。

运行容器 (进入容器):
lxc exec c1 bash
查找 netplan 网络设置文件:
ls /etc/netplan

得知是
50-cloud-init.yaml
/etc/netplan/50-cloud-init.yaml 的内容
network:
    version: 2
    ethernets:
        eth0:
            dhcp4: true
修改 /etc/netplan/50-cloud-init.yaml 的内容为固定 IP。
network:
    version: 2
    ethernets:
        eth0:
            # dhcp4: true
            addresses: [192.168.1.101/24]
            gateway4: 192.168.1.254
            nameservers:
              addresses: [192.168.1.254]
以 netplan apply 直接变更:
netplan apply
检查一下 IP 是否合乎预期
ip -c a

LXD 远程服务

LXD 增加远程服务的功能要设置要监听(Listen)的 IP 位置及连接端口。

lxc config set core.https_address :8443
查看 8443 监听情况:
netstat -nltp | grep 8443

tcp6       0      0 :::8443                 :::*                    LISTEN      823/lxd

虽然只有 tcp6,但在其他只有 IPv4 的主机,连接并无问题。

LXD 远程服务需要设置连接密码:

lxc config set core.trust_password myPassword

LXD 4.0 (含以上) 本地端添加远程主机,可能会出错。

lxc remote add myServer
Error: Get "https://myServer:8443": lookup myServer: Temporary failure in name resolution

无法加入 myServer,但 ping myServer 是正确的。
LXD 4.0 (含以上) 是用 lookup,它忽略了 /etc/nsswitch.confhost 协定设置如 wins

参阅 DNS 解析服务 设置正确的 DNS 服务器。


本地端添加远程主机

添加远程主机(远程主机即为远程名称):
lxc remote add myServer

设置远程名称及主机实际 IP(或名称):
lxc remote add myServer 192.168.1.21

Ubuntu 16 (LXD 2.0.11) 需要指明两者:
lxc remote add myServer myServer

连接时,可确认 fingerprint 的正确性,fingerprint 可在远程服务器运行 lxc info 得知。

Generating a client certificate. This may take a minute...
Certificate fingerprint: 512a711cc2618105624d09525ce997823e895de6d5f7b775316dbc51d1aa728b
ok (y/n)? y
Admin password for myServer:
Client certificate stored at server:  myServer
移除远程主机:
lxc remote remove myServer

再次加入相同的远程主机:
lxc remote add myServer

第二次没有要求输入密码

远程服务主机在(被)用户端连接时,凭证会在初次连接时产生,可通过下列命令管理:

列出受信任的用户端:
lxc config trust ls

+--------------+--------------+------------------------------+------------------------------+
| FINGERPRINT  | COMMON NAME  |          ISSUE DATE          |         EXPIRY DATE          |
+--------------+--------------+------------------------------+------------------------------+
| d08f211a7849 | user@host1   | Dec 9, 2022 at 12:25am (UTC) | Dec 6, 2032 at 12:25am (UTC) |
+--------------+--------------+------------------------------+------------------------------+
移除用户端凭证:
lxc config trust remove d08f211a7849

移除凭证后,该用户端操作远程服务的功能时会显示错误

$ lxc list myServer:

Error: not authorized

用户端需移除远程主机,再添加远程主机,添加远程主机时则会要求输入密码。


服务器要设置为 IPv4 可以采用本机的 IPv4 的 IP 位置来监听:

lxc config set core.https_address 192.168.1.21:8443

如果要以本机名称监听 IPv4,先把 /etc/hosts 内的本机位置注掉或删除 (否则监听的位置为 127.0.1.1):

127.0.0.1       localhost
#127.0.1.1       myServer (1)

# The following lines are desirable for IPv6 capable hosts
...
1 注掉该行
再来以本机名称监听:
lxc config set core.https_address myServer:8443
查看 8443 监听情况:
netstat -nltp | grep 8443

tcp        0      0 192.168.1.21:8443      0.0.0.0:*               LISTEN      2737/lxd
检查一下 LXD 的设置:
lxc config show

config:
  core.https_address: myServer:8443
  core.trust_password: true

要取消 LXD 的服务器功能,运行下列:

lxc config unset core.https_address

如果连接密码也要取消,运行下列:

lxc config unset core.trust_password

在不同版本的 LXD 如 4.0 5.0,远程连接时会有些状况:

Error: Get "https://myServer:8443": tls: server selected unsupported protocol version 303
Error: Get https://myServer:8443/1.0: remote error: tls: protocol version not supported

远程连接的 LXD 版本应该要一致,如果无法一致以拷贝文件 (如导出容器文件、容器影像档) 方式来解决 。

LXD 3.0.3 4.0.9

本地端 LXD 版本 3.0.3 (myhost),远程 4.0.9 (myServer),可正确运行 lxc list myServer: (列示远程容器)、lxc copy myServer:c1 c1 (拷贝远程容器至本机),但奇怪的是由本机「发送」容器至远程出现下列错误:

拷贝容器至远程:
lxc copy c1 myServer:c1

Error: Failed container creation: Error transferring instance data: lookup : no such host

改由 4.0.9 「接收」 3.0.3, lxc copy myhost:c1 c1 则正确,再测试 4.0.9 「发送」至 3.0.3 lxc copy c1 myhost:c1 也正确。

LXD 3.0.3 采用 IP 位置
本地端添加远程主机:
lxc remote add 192.168.1.21

本地端列出远程容器:
lxc list 192.168.1.21:

(无错误)

拷贝容器至远程:
lxc copy c1 192.168.1.21:c1

Error: Failed container creation: Error transferring instance data: lookup : no such host

LXD 快照

让容器变成不同:

在容器内置立一个文件:
lxc exec c1 -- touch snap0File

列出创建的文件:
lxc exec c1 -- ls

snap0File

创建快照:

创建 snap0 快照:
lxc snapshot c1

会创建一个名称为 snapN 的快照,其中 N 是一个递增的数字。
创建命名为 mySnapshot1 的快照:
lxc snapshot c1 mySnapshot1

查找快照:

$lxc info c1

...
Snapshots:
  snap0 (taken at 2022/12/08 16:13 CST) (stateless)
  mySnapshot1 (taken at 2022/12/08 16:16 CST) (stateless)

删除自订命名的 mySnapshot1 快照:

lxc delete c1/mySnapshot1

让容器变成不同:

在容器内,删除 snap0File, 再创建另一个文件:
lxc exec c1 -- rm snap0File
lxc exec c1 -- touch NewFile

列示文件:
lxc exec c1 -- ls

NewFile

恢复快照:

恢复 snap0 快照:
lxc restore c1 snap0

列示文件:
lxc exec c1 -- ls

snap0File

LXD 容器 转移/备份

lxc copy

容器拷贝,命令格式如下:

lxc copy [远程:]来源容器[/快照名称] [[远程:]目标容器] [选项]

lxc copy 选项

--instance-only

只备份实例(无快照)。

容器拷贝 (缺省含快照)

本机拷贝容器:
lxc copy c1 c3

拷贝本机容器至远程:
lxc copy c1 myServer:c1

拷贝远程容器至本机:
lxc copy myServer:c1 c1

容器快照拷贝 (由于已指明快照,将不拷贝其他快照)。

当容器快照有多个时,如快照顺序为 snap0 → mySnapshot1,恢复前一个快照,将会错误。

查找快照:
lxc info c1

...
Snapshots:
  snap0 (taken at 2022/12/08 16:13 CST) (stateless)
  mySnapshot1 (taken at 2022/12/08 16:16 CST) (stateless)

恢复 snap0 快照:
lxc restore c1 snap0

Error: Snapshot "snap0" cannot be restored due to subsequent snapshot(s). Set zfs.remove_snapshots to override

采用容器拷贝来处理

将容器 c1 的快照 snap0 拷贝至容器 c1-s0:
lxc copy c1/snap0 c1-s0

lxc export

在 LXD 4.0 (含以后),增加 export / import 指令,能运行导出、导入的动作。
容器名称是由导出的内容来决定,因此,在导出时其文件名称应为容器名称作为辨识。

容器导出,命令格式如下:
lxc export [远程:]容器 [目标] [选项]
lxc export 选项

--compression

指定压缩格式支持 bzip2、gz、xz、lzma。

--instance-only

只备份实例(无快照)。

--optimized-storage

根据 help 说明: Use storage driver optimized format (can only be restored on a similar pool), 使用保存驱动进程优化格式(只能在类似的池上恢复)。

导出容器 (缺省含快照)
$ lxc export c1 c1.tar
Backup exported successfully!
可采用 --compression 指定压缩格式。
$ lxc export c1 c1.bz2 --compression bzip2
Backup exported successfully!

导入容器
其容器名称由文件的内容来决定,无法变更,如果跟现有容器的名称相同则会出错。

lxc import c1.tar

比较一下 LXD Version 4.0.9 在不同的选项、压缩格式的大小及时间。
注:LXD Version 5.8 的大小及时间合乎预期。

time lxc export c1 c1.tar
time lxc export c1 c1.bz2 --compression bzip2
time lxc export c1 c1.gz --compression gzip
time lxc export c1 c1.lzma --compression lzma
time lxc export c1 c1.xz --compression xz

time lxc export c1 c1-os.tar --optimized-storage
time lxc export c1 c1-os.bz2 --compression bzip2 --optimized-storage
time lxc export c1 c1-os.gz --compression gzip --optimized-storage
time lxc export c1 c1-os.lzma --compression lzma --optimized-storage
time lxc export c1 c1-os.xz --compression xz --optimized-storage
文件 大小 时间

c1.lzma

206M

9m37.185s

c1.xz

206M

10m2.886s

c1.bz2

285M

2m11.167s

c1.gz

321M

1m0.046s

c1.tar

321M

0m59.767s

文件 大小 时间

c1-os.lzma

206M

9m37.185s

c1-os.xz

206M

9m50.637s

c1-os.bz2

285M

2m2.900s

c1-os.gz

321M

1m1.752s

c1-os.tar

321M

1m1.419s

lxc publish

将目前的容器发布成影像档,命令格式如下:
lxc publish 容器名称[/快照名称] [远程] [选项]
lxc publish 选项

--alias

指定影像档别名。

--compression

指定压缩格式支持 bzip2、gz、xz、lzma。

-f, --force

如果容器正在运行,自动停止。

将容器发布成影像档

将容器 c1 发布成 my_c1 影像档:
lxc publish c1 --alias my_c1

Instance published with fingerprint: fca9356c123004273d9673df8188321da84020df164d09fe257ed727cb310a44

列示影像档:
lxc image list -c lfda

+-------+--------------+------------------------------------+--------------+
| ALIAS | FINGERPRINT  |            DESCRIPTION             | ARCHITECTURE |
+-------+--------------+------------------------------------+--------------+
| my_c1 | fca9356c1230 | Ubuntu 18.04 LTS server (20221201) | x86_64       |
+-------+--------------+------------------------------------+--------------+

容器以影像档发送至远程

lxc publish c1 --alias my_c1 myServer:

由影像档创建(初始化)容器:

由别名创建容器 c3:
lxc init my_c1 c3

由 fingerprint 创建容器 c4:
lxc init fca9356c1230 c4

将影像档导出成文件

影像档 my_c1 导出文件:
lxc image export my_c1

Image exported successfully!

输出的文件为
fca9356c123004273d9673df8188321da84020df164d09fe257ed727cb310a44.tar.gz

影像档导出指定文件名:
lxc image export my_c1 my_c1

输出的文件为
my_c1.tar.gz

删除影像档

lxc image delete my_c1

LXD 其他命令 (exec、file)

lxc exec 运行容器

运行容器命令格式:
lxc exec [远程:]容器 [--] 命令行

运行容器:
lxc exec c1 bash

容器运行指令:
lxc exec c1 -- cat /etc/hosts

lxc file 可运行如下命令

delete 删除容器内的文件
edit   编辑容器内的文件
pull   取出容器内的文件
push   将文件写入到容器

取出容器文件

取出容器文件的命令格式:
lxc file pull [远程:]容器/<路径> [[远程:]容器/<路径>...] 目标路径

容器内的文件输出至标准输出:
lxc file pull c1/etc/hosts -

容器内的文件写入至目前路径:
lxc file pull c1/etc/hosts .

取出远程容器的文件输出至标准输出:
lxc file pull myServer/etc/hosts -

写入容器文件的命令格式如下(不再示例):

lxc file push <来源路径> [远程:]容器/<路径> [[远程:]容器/<路径>...]

(以常用的编辑器) 编辑容器内文件

编辑容器内文件的命令格式:
lxc file edit [远程:]容器/<路径>

编辑 c1 容器的 /etc/hosts
lxc file edit c1/etc/hosts

更新(迁移) LXD 版本

Ubuntu 16 / 18 (非以 Snap) 安装 LXD,迁移至 Snap LXD。

在迁移 LXD 版本前最好先备份容器。
以 root 帐户运行 (不想每次输入 sudo):
su

检查目前的版本:
lxd --version

确定容器保存路径是否包含 c1 c2 (注:「lXD 创建容器」范例中创建两个容器):
ls /var/lib/lxd/containers

c1  c2
安装 Snap
apt install snapd -y

查找 Snap 版本:
snap version

snap    2.57.5+18.04ubuntu0.1
snapd   2.57.5+18.04ubuntu0.1
series  16
ubuntu  18.04
kernel  4.15.0-118-generic
安装 LXD 4.0 稳定版
snap install lxd --channel=4.0/stable

检查目前的版本:
lxd --version

还没有迁移,版本没变。
运行迁移
lxd.migrate

Are you ready to proceed (yes/no) [default=no]? yes
你准备好继续了吗? 当然要输入 yes。

在迁移的过程中,会停止原始 (旧) 的 LXD:
=> Shutting down the source LXD
=> Stopping the source LXD units
=> Stopping the destination LXD unit
=> Unmounting source LXD paths
=> Unmounting destination LXD paths
=> Wiping destination LXD clean
=> Backing up the database
=> Moving the data
=> Updating the storage backends
=> Starting the destination LXD
=> Waiting for LXD to come online


Do you want to uninstall the old LXD (yes/no) [default=yes]?
你要卸载旧有的 LXD 吗?  按下 Enter (默认值为 yes)

迁移完成后如下消息:
All done. You may need to close your current shell and open a new one to have the "lxc" command work.
To migrate your existing client configuration, move ~/.config/lxc to ~/snap/lxd/common/config
迁移后,LXD 程序路径已变更
迁移后,运行 LXD 会出错,因为 LXD 程序路径已改变成 Snap 的路径:
lxd version

-bash: /usr/bin/lxd: No such file or directory

重置 bash 记忆程序的路径:
hash -r

再运行 lxd 应该正确:
lxd version

4.0.9

检查容器是否迁移:
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
+------+---------+----------------------+----------+
LXD 容器的保存位置已变更
LXD 容器的保存位置已变更, 错误是正常的:
ls /var/lib/lxd/containers

ls: cannot access '/var/lib/lxd/containers': No such file or directory

Snap 的 LXD 位置 /var/snap/lxd/common/lxd 同等于 /var/lib/lxd:
ls /var/snap/lxd/common/lxd/containers

c1  c2

Snap LXD 更新版本

更新版本后可能无法降级,更新版本前应先备份容器。
以 root 帐户运行 (不想每次输入 sudo):
su

检查目前的版本:
lxd version

4.0.9
安装最新稳定版:
snap install lxd --channel=latest/stable

snap "lxd" is already installed, see 'snap help refresh'
install 出错,要采用 refresh。

升级为最新稳定版:
snap refresh lxd --channel=latest/stable

检查一下版本:
lxd version

5.8

检查容器是否存在:
lxc list -c ns4P

+------+---------+----------------------+----------+
| NAME |  STATE  |         IPV4         | PROFILES |
+------+---------+----------------------+----------+
| c1   | RUNNING | 192.168.1.101 (eth0) | default  |
+------+---------+----------------------+----------+
| c2   | RUNNING | 192.168.1.102 (eth0) | default  |
+------+---------+----------------------+----------+

Snap LXD 版本降级测试,实测会出错。可能有解决方式,但需要时间研究。

由 LXD 5.8 降级成 4.0 稳定版, 运行出错:
snap refresh lxd --channel=4.0/stable

2022-12-08T04:10:01+08:00 INFO Waiting for "snap.lxd.daemon.service" to stop.
error: cannot perform the following tasks:
- Start snap "lxd" (24061) services (systemctl command [start snap.lxd.activate.service] failed with exit status 1: Job for snap.lxd.activate.service failed because the control process exited with error code.
See "systemctl status snap.lxd.activate.service" and "journalctl -xe" for details.
)

版本未变更:
lxd version

5.8

降级成 LXD 3.0 稳定版, 运行后并未显示错误 (注:由 4.0 降级 3.0 也未显示错误):
snap refresh lxd --channel=3.0/stable

2022-12-10T21:48:12Z INFO Waiting for "snap.lxd.daemon.service" to stop.
lxd (3.0/stable) 3.0.4 from Canonical✓ refreshed

检查版本:
lxd version

3.0.4

但事实上已经出错:
lxc list

If this is your first time running LXD on this machine, you should also run: lxd init
To start your first container, try: lxc launch ubuntu:18.04

Error: Get http://unix.socket/1.0: dial unix /var/snap/lxd/common/lxd/unix.socket: connect: connection refused

错误说明中提到 lxd init (已经运行过了), 那就试试看:
lxd init

Error: Failed to connect to local LXD: Get http://unix.socket/1.0: dial unix /var/snap/lxd/common/lxd/unix.socket: connect: connection refused

LXD 没有监听:
netstat -lnp | grep lxd

已知 LXD 服务未启动:
snap start lxd

error: cannot perform the following tasks:
- Run service command "start" for services ["activate" "daemon"] of snap "lxd" (systemctl command [start snap.lxd.activate.service] failed with exit status 1: Job for snap.lxd.activate.service failed because the control process exited with error code.
See "systemctl status snap.lxd.activate.service" and "journalctl -xe" for details.
)

试着更新成 LXD 4.0 稳定版, 挂掉:
snap refresh lxd --channel=4.0/stable

Start snap "lxd" (24061) services
Start snap "lxd" (24061) services
Start snap "lxd" (24061) services
...

在另一个终端机检查 Snap LXD 版本:
snap list

Name    Version        Rev    Tracking       Publisher   Notes
core    16-2.57.6      14399  latest/stable  canonical✓  core
core20  20221123       1738   latest/stable  canonical✓  base
lxd     4.0.9-a29c6f1  24061  4.0/stable     canonical✓  -
snapd   2.57.6         17883  latest/stable  canonical✓  snapd

重开机后启动 LXD:
lxd

WARN[12-10|22:19:54]  - Couldn't find the CGroup blkio.weight, disk priority will be ignored
WARN[12-10|22:19:54]  - Couldn't find the CGroup memory swap accounting, swap limits will be ignored
WARN[12-10|22:19:54] Instance type not operational            type=virtual-machine driver=qemu err="KVM support is missing"
EROR[12-10|22:19:54] Failed to start the daemon               err="Error creating database: schema version '43' is more recent than expected '42'"
Error: Error creating database: schema version '43' is more recent than expected '42'

LXD 错误消息

下列的问题及解答(或原因),其「解答(或原因)」并非唯一答案,会有其他操作而有相同错误消息的情况。

  1. Error: Get "http://unix.socket/1.0": dial unix /var/snap/lxd/common/lxd/unix.socket: connect: permission denied

    目前用户不在 lxd 群组。

  2. Error: Get http://unix.socket/1.0: dial unix /var/snap/lxd/common/lxd/unix.socket: connect: connection refused

    升降级 LXD 后运行 lxc list 出错,LXD 服务未启动。

  3. Error: Get https://myServer:8443/1.0: x509: certificate signed by unknown authority (possibly because of "x509: ECDSA verification failure" while trying to verify candidate authority certificate "root@myServer")

    远程主机凭证不正确,可能是重新安装 LXD 造成。

    重新加入远程主机可解决
    lxc remote remove myServer
    lxc remote add myServer
  4. Error: not authorized

    远程主机移除用户端凭证,如远程主机运行 lxc config trust remove <hostname|fingerprint>
    重新加入远程主机可解决。

  5. Unable to connect to: myServer:8443

    远程主机 myServer 未激活远程服务。

  6. lookup myServer: Temporary failure in name resolution

    本机 DNS 解析服务不正确。

  7. lookup myServer: device or resource busy

    本机对远程主机 myServer 操作,本机 DNS 解析服务不正确。

  8. Error transferring instance data: lookup myhost: device or resource busy

    本机 myhost 拷贝容器至远程主机,错误消息是 myhost,远程主机 DNS 解析服务设置不正确。

LXD 命令示例

影像档类
lxc image list
lxc image export myContainer myContainer

lxc publish 容器名称[/快照名称] [远程] [选项]
lxc publish myContainer --alias myImage
lxc profile
lxc profile list
lxc profile create myProfile
lxc profile show myProfile
lxc profile rename myProfile MyProfile
lxc profile add myContainer myProfile
lxc profile remove myContainer myProfile
lxc profile assign myContainer default,myProfile
容器类
lxc list -c ns4P
lxc init ubuntu:18.04 myContainer -p default -p myProfile
lxc launch ubuntu:18.04 myContainer -p default -p myProfile
lxc start myContainer
lxc restart myContainer
lxc pause myContainer
lxc stop myContainer
lxc delete myContainer
lxc rename myContainer MyContainer

lxc copy [远程:]来源[/快照] [[远程:]目标] [选项]
lxc copy myContainer MyContainer
运行容器
lxc exec [远程:]容器 [--] 命令行
lxc exec myContainer bash
lxc exec myContainer -- cat /etc/hosts
容器文件处理
lxc file pull [远程:]容器/<路径> [[远程:]容器/<路径>...] 目标路径
lxc file pull myContainer/etc/hosts -
lxc file pull myServer/etc/hosts -

lxc file push <来源路径> [远程:]容器/<路径> [[远程:]容器/<路径>...]

lxc file edit [远程:]容器/<路径>
lxc file edit myContainer/etc/hosts
lxc remote
lxc remote list
lxc remote add myServer
lxc remote remove myServer
lxc config
lxc config set core.https_address :8443
lxc config set core.trust_password myPassword
lxc config unset core.trust_password
lxc config show
lxc config show myContainer
其他
lxc info
lxc info myContainer

设备设置

lxc network
lxc network list
lxc network show lxdbr0
lxc network attach lxdbr0 myContainer eth0 eth0
lxc network detach lxdbr0 myContainer
lxc network set lxdbr0 ipv4.firewall false
lxc network set lxdbr0 ipv6.nat false
lxc config device
lxc config device add myContainer eth0 nic nictype=bridged parent=lxdbr0 name=eth0
lxc config device remove myContainer eth0
lxc config device unset myContainer eth0 name
lxc config device set myContainer eth0 name eth0
lxc config device list myContainer
lxc profile device
lxc profile device add myProfile eth0 nic nictype=bridged parent=br0 name=eth0
lxc profile device unset myProfile eth0 name
lxc profile device set myProfile eth0 name eth0
lxc profile device set myProfile eth0 parent br0
lxc profile device set myProfile eth0 nictype bridged
lxc profile device remove myProfile eth0