Note
|
由于 LXC 和 LXD 目前与 Ubuntu 的适配度最高,因此所有的操作均在 Ubuntu 下完成 |
在 WSL2 上使用 LXD 有以下几个问题
-
lxd 需要 systemd 支持,因此 Ubuntu 必须以 systemd 作为 init 程序
-
lxd 通过 snapcraft.io 发布,也就是说要安装 lxd 先得安装 snapd
-
snapcraft.io 没有镜像源,因此下载速度很慢
-
要保证 lxd 容器的隔离,需要启用 AppArmor,但是 apparmor 需要内核支持,而 Windows 官方给出的内核不支持 AppArmor
根据我的测试,使用 WSL2 官方仓库 开启 AppArmor 内核编译选项,并重新编译,并不能正确在 Ubuntu 下检测到 AppArmor
依照 #8709 的说法,https://github.com/diddlesnaps/WSL2-Linux-Kernel 提供了 AppArmor 的支持
于是从上面的仓库中下载编译好的内核,在 Windows %USERPROFILE%\.wslconfig
添加/修改如下内容
[wsl2]
kernel = <下载的 kernel 的路径>
Note
|
注意,是 |
apt install snapd
安装 snapd 的同时,会安装 AppArmor;关于 Apparmor,我们需要做一些额外的配置
虽然我们使用的内核已经支持了 AppArmor,但由于是在 WSL 中运行的 Ubuntu,因此 securityfs
这个重要的组件没有被自动挂载,这里我们需要写一个 service,让其可以自动挂载
依照 #8840 的说法,创建 /etc/systemd/system/mount_securityfs.service
[Unit]
Description=Kernel Security File System
DefaultDependencies=no
Before=sysinit.target
Before=apparmor.service
ConditionSecurity=apparmor
ConditionPathIsMountPoint=!/sys/kernel/security
[Service]
Type=oneshot
ExecStart=/bin/mount -t securityfs -o nosuid,nodev,noexec securityfs /sys/kernel/security
[Install]
WantedBy=sysinit.target
并启用它
systemctl daemon-reload
systemctl enable --now mount_securityfs.service
systemctl restart apparmor.service
目前,snapcraft.io 还没有任何的镜像源,因此下载 snap 包可能会非常慢,因此在下载前可以配置代理,以提速
Note
|
snapd 是运行在后台的服务,因此通过 bash 的环境变量是无法影响到 snapd 的 |
# 如果 snapd 还没有启动,则手动启动一下
# systemctl start snapd.service
# 代理的 IP 地址是 Windows 的 vEthernet (WSL) 的地址
snap set system proxy.https="<代理地址>"
接着安装 lxd
snap install lxd
初次安装时,snap 会额外下载 snapd 和 core 包,请耐心等待
安装完成后,系统中会多出一些 systemd unit,与 lxd 相关的均以 snap.lxd 开头
Note
|
下面要介绍的配置方法为全手动配置的方法。 |
存储池是 lxd 托管的各个容器(container)的数据的存储中心。除非额外挂载外部的磁盘/文件,每个容器的文件都存储在某个存储池中。
上面的话暗含了两个要点,第一,在没有额外挂载的情况下,某一时刻,一个容器的数据能且仅能存储在一个存储池中;第二,一个存储池中可以存储多个容器的数据。
让我们实际创建一个存储池
# 创建一个名为 main_storage,格式为 btrfs,容量为 8GiB 的存储池
lxc storage create main_storage btrfs size=8GiB
# 罗列 lxd 中所有的存储池
lxc storage list
# 查看 main_storage 的详细信息
lxc storage show main_storage
容器需要联网,或者不同容器之间需要通过网络通信,那么我们就可以创建虚拟网络接口来实现
# 创建一个名为 main_bridge 的网桥
# 设置网桥的 IPv4 地址,该地址会作为 DHCP 和 DNS 服务器的地址
# 允许 IPv4 NAT,让容器可以访问外部
# 启用 DHCP 服务器
# 设置 DHCP 服务器发放地址的范围
# 禁用 IPv6
# 禁用 IPv6 NAT
lxc network create main_bridge --type bridge \
ipv4.address=10.0.0.1/24 \
ipv4.nat=true \
ipv4.dhcp=true \
ipv4.dhcp.ranges=10.0.0.100-10.0.0.200 \
ipv6.address=none \
ipv6.nat=false
# 罗列 lxd 中所有的网络界面
# 注意,这个命令还会罗列可以被 LXD 使用,但不被 LXD 管理的操作系统提供的网络接口
lxc network list
# 显示 main_bridge 的详细信息
lxc network show main_bridge
不知道为什么,我的 LXD 自带的 dnsmasq 无法读取 /etc/resolv.conf
,journalctl -xe
提示 Permission denied
。
这导致我在容器中使用 resolvectl query
的时候返回 Refused
。
这里只能手动指定一个远程 DNS 服务器了。
lxc network set main_bridge raw.dnsmasq="server=114.114.114.114"
Profile 相当于创建容器时的配置信息,LXD 自带一个不可删除的 profile,其名为 default
这里我们需要将上面创建的存储池和虚拟网络接口关联至 default
profile 中,这样在每次创建容器时,都会使用这套默认配置
# 在 default profile 中的 device 条目下,
# 创建名为 default_pool 的条目(该名称仅用于在 profile 中辨识用)
# 创建的设备为磁盘 disk
# 挂载路径为根目录 /(path=/ 使用存储池的固定写法)
# 使用的存储池为 main_storage(pool=main_storage)
lxc profile device add default default_pool disk path=/ pool=main_storage
# 在 default profile 中的 device 条目下,
# 创建名为 default_nic 的条目(该名称仅用于在 profile 中辨识用)
# 创建的设备为网卡 nic
# 网卡在容器中的名称为 eth0(name=eth0)
# 网卡的类型为已桥接,表示该网卡将连接至一个已有的网桥上(nictype=bridged)
# 已有的网桥的名称为 main_bridge(parent=main_bridge)
lxc profile device add default default_nic nic name=eth0 nictype=bridged parent=main_bridge
# 禁用 image 自动更新
lxc config set images.auto_update_interval 0
# 启用 image 自动更新
lxc config unset images.auto_update_interval
鉴于网络原因,默认的远程仓库很慢,不过清华大学的镜像源提供了 lxc image 的镜像,我们可以配置一下
# 参考 https://mirrors.tuna.tsinghua.edu.cn/help/lxc-images/ 的方案
# 添加 tuna-images 源
lxc remote add tuna-images https://mirrors.tuna.tsinghua.edu.cn/lxc-images --protocol=simplestreams --public
# 查看一下 tuna-images 中具有的 images
lxc image list tuna-images:
虽然我们可以直接从远程拉取一个 image,并创建一个容器,这里我们还是选择先下载一个 image,之后再从本地 image 创建容器
# 从 tuna-image: 将 ubunut/22.10 拷贝至本地存储 local:,并将本地的 image 命名为 ubuntu22.10
lxc image copy tuna-images:ubuntu/22.10 local: --alias ubuntu22.10
# 从本地存储的 ubuntu 镜像中创建一个名为 ubuntu-22-10 的容器
# 注意容器名只能由英文字母、数字和横线组成
lxc launch local:ubuntu22.10 ubuntu-22-10
创建容器之后,由于 root 账户没有任何密码,因此无法正确登陆,此时我们可以先通过 lxc shell
获得一个容器 root 级别的 shell,再通过 passwd 为 root 账户设置一个密码
# 要求 lxc 返回容器的一个 shell
lxc shell ubuntu-22-10
# 此时已处在容器中
# 设置容器的 root 账户的密码
passwd
# 退出容器的 shell
exit
可以通过 lxc console 连接至容器的控制台
Important
|
要退出容器 console,使用组合键 kbd:[ctrl+a] 之后 kbd:[q] |
lxc console ubuntu-22-10