We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
创建一个基于CT 模板为alpine 的 LXC 容器,启动之后需要修改源和安装 docker
https://mirrors.ustc.edu.cn/alpine/latest-stable/main https://mirrors.ustc.edu.cn/alpine/latest-stable/community #https://mirrors.ustc.edu.cn/alpine/edge/main #https://mirrors.ustc.edu.cn/alpine/edge/community
apk update apk add docker docker-compose
将设备挂载入容器的前提,必须对 cgroup2 进行设置,lxc.cgroup2.devices.allow: b *:* rwm,b 表示块设备,设备号可以使用 ls -l /dev 或者 lsblk 查看,: 表示所有设备号
lxc.cgroup2.devices.allow: b *:* rwm
ls -l /dev
lsblk
lxc.cgroup2.devices.allow: b *:* rwm lxc.cgroup2.devices.allow: c *:* rwm lxc.mount.entry: /dev/sda dev/sda none bind,create=file # 对单个设备挂载入lxc容器
创建设备文件也可以使用 autodev hook 实现,这个脚本实现了所有块设备的创建。
autodev hook
lxc.autodev: 1 lxc.hook.autodev: sh -c 'cat /proc/partitions | awk '"'"'{if ($1~/[0-9]+/) system("mknod -m 777 ${LXC_ROOTFS_MOUNT}/dev/"$4" b "$1" "$2)}'"'"''
后续,容器使用过程中,例如硬盘重新分区,usb 等热插拔设备,想让容器能够获取到设备最新状态,可以运行下列命令:
cat /proc/partitions | awk '{if ($1~/[0-9]+/) system("rm ${LXC_ROOTFS_MOUNT}/dev/"$4" ;; mknod -m 777 ${LXC_ROOTFS_MOUNT}/dev/"$4" b "$1" "$2)}'
同样的,与块设备一样,只需对 cgroup2 进行设置 lxc.cgroup2.devices.allow: c *:* rwm,c 表示字符设备,设备号可以使用 ls -l /dev查看,: 表示所有设备号
lxc.cgroup2.devices.allow: c *:* rwm
lxc.cgroup2.devices.allow: c *:* rwm lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file # 将tun设备挂入 lxc 容器, 可以实现 tailscale/wireguard 等 lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file #intel 核显设备
** 可能会出现意想不到的问题 **
再进一步,如果要对所有设备进行直通,可以使用,lxc.cgroup2.devices.alllow: a 表示允许所有设备,但是如何对所有文件挂载进入 lxc 容器的,同时,如果设备文件发生变化,例如硬盘重新分区,usb 等热插拔设备,需要让容器能够获取到,就需要一些小小的魔法,这里将 /dev 目录挂载为 overlayfs 并挂入容器内部,这样,lxc 容器就能直接使用 /dev 内的内容了。
lxc.cgroup2.devices.alllow: a
/dev
lxc.cgroup2.devices.alllow: a lxc.hook.pre-mount: sh -c "umount /tmp/.ct0_dev/merge 2&> /dev/null; rm -fr /tmp/.ct0_dev; mkdir -p /tmp/.ct0_dev/upper /tmp/.ct0_dev/work /tmp/.ct0_dev/merge; mount -t overlay overlay -o lowerdir=/dev,upperdir=/tmp/.ct0_dev/upper,workdir=/tmp/.ct0_dev/work /tmp/.ct0_dev/merge" # 在/tmp/.ct0_dev/merge 创建 /dev 对 overlayfs lxc.mount.entry: /tmp/.ct0_dev/merge dev none bind,create=dir # 挂载入容器 lxc.hook.post-stop: sh -c "umount /tmp/.ct0_dev/merge 2&> /dev/null; rm -fr /tmp/.ct0_dev" # 在关闭容器的时候销毁 overlayfs
默认情况下,pve 会给容器通过 veth 网桥来分配虚拟网卡,如果 pve 主机有多个网卡,可以将网卡直通入 lxc:
lxc.net.0.type: phys lxc.net.0.link: enp1s0 lxc.net.0.name: eth0 lxc.net.1.ipv4.address: 10.1.1.222 lxc.net.1.ipv4.gateway: 10.1.1.1 lxc.net.1.flags: up
只有一张网卡的情况,使用 macvlan 会比 veth 带来更好的性能表现:
xc.net.1.type: macvlan lxc.net.1.link: vmbr0 lxc.net.1.name: eth0 lxc.net.1.ipv4.address: 10.1.1.222 lxc.net.1.ipv4.gateway: 10.1.1.1 lxc.net.1.flags: up
挂载 /volumes 以及 fstab 的目的是,计划通过编辑容器内的 /tmp/fstab 来实现PVE宿主开机自动挂载到 /volumes 目录中,使用 rbind参数使其,具有挂载传播性,即:宿主机挂载硬盘,在容器中也能看到。
/volumes
fstab
/tmp/fstab
rbind
lxc.mount.entry: /volumes volumes none rbind,create=dir lxc.mount.entry: /etc/fstab tmp/fstab none bind,create=file
创建挂载的目录,同时为了保护 /meida 目录下的 disk* 目录,可以使用chattr修改权限
mkdir -p /volumes/disk{0..9} chattr +i /volumes/disk{0..9}
创建完目录之后,可以挂载硬盘,当然如果是新硬盘,要分区格式化
mount /dev/sdXn /volumes/disk* # 根据自己情况修改
挂载完成所有硬盘之后,可以将相关挂载信息写入fstab,以便下次重启,自动挂载,这里写了一个小脚本来帮助填写
#!/bin/bash MEDIA=/volumes # 获取所有分区设备 partitions=$(lsblk -o UUID,MOUNTPOINT -n -l | grep -E "\s+${MEDIA}/\w+$") # 遍历每个分区 while IFS= read -r partition; do # 提取分区名称、UUID 和挂载点 uuid=$(echo $partition | awk '{print $1}') mountpoint=$(echo $partition | awk '{print $2}') # 添加分区挂载信息到 fstab echo "UUID=$uuid $mountpoint auto defaults 0 0" done <<< "$partitions"
执行之后,会输出相应的配置,只要追加复制到 /etc/fstab 就行了
考虑到写入 fstab后,如果硬盘出现问题或者硬盘拔出后,会在启动时报错,所以考虑在容器启动时执行用脚本挂载操作。 而使用 mp0=/dev/sdaX...则会导致每次重启容器都需要卸载和挂载,带来不必要的操作。 同样创建完目录之后,可以挂载硬盘,当然如果是新硬盘,要分区格式化
mp0=/dev/sdaX...
mount /dev/sdXn /volumes/disk* # 根据自己情况修改 lsblk -o UUID,MOUNTPOINT -n -l | grep -E "\s+/volumes/\w+$" > /root/mttab # 创建uuid和挂载目录一一对应的文件 cat /root/mount.sh # mount.sh 内容: #!/bin/sh DF=$(mount) MEDIA="/volumes" LSBLK=$(lsblk -o UUID,MOUNTPOINT -n -l | grep -E "\s+${MEDIA}/\w+$") cat /root/mttab | while read line do uuid=$(echo $line | awk '{print $1}') mountpoint=$(echo $line | awk '{print $2}') [ -n "$(echo ${LSBLK} | grep ${uuid})" ] || mount /dev/disk/by-uuid/$uuid $mountpoint done # 修改lxc 配置文件: lxc.hook.pre-start: /root/mount.sh
lxc.mount.auto: proc:rw sys:rw cgroup-full:rw lxc.mount.entry: tmp tmp tmpfs rw,nodev,relatime,mode=1777 0 0
禁用 AppArmor 提升容器权限,lxc.cap.drop 空表示容器支持所有 Linux Capabilities 权限,进一步提升权限,可以使用 capsh --print 查看,可以使用smartctl 查看磁盘 S.M.A.R.T. 信息
lxc.apparmor.profile: unconfined lxc.cap.drop:
lxc 可以支持 clone/keep/share 等方式将宿主机的 namespaces 与容器共用。 可以使用 lxc.namespace.keep lxc.namespace.clone lxc.namespace.share.* 这三个参数进行设置,详情可以查看 man page。
lxc.namespace.keep
lxc.namespace.clone
lxc.namespace.share.*
但是 pve 的 pct 配置文件并不支持者三个参数,可以使用下面这个补丁来解除限制:
sed -i '/my $valid_lxc_conf_keys = {/a\ '"'"'lxc.namespace.keep'"'"' => 1,\n '"'"'lxc.namespace.clone'"'"' => 1,\n '"'"'lxc.namespace.share.*'"'"' => 1,' /usr/share/perl5/PVE/LXC/Config.pm
# 与宿主共享网络,相当于 docker 的 host 网络 lxc.namespace.keep: net # 与共享宿主的 pid,相当于 docker 的 --pid=host,相当于 chroot,但是共享 pid 会导致容器中的 init 程序会无法启动,从而导致容器失败,解决办法是把容器的启动命令改成其他的,例如tini,存在的问题是,无法使用 console 进入,可以使用 pct enter 进入,我这里只直接配置了启动 dockerd: lxc.namespace.keep:user pid net lxc.init.cmd: env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /sbin/tini-static -sg -- dockerd
lxc 默认的 stop 信号是 SIGKILL,这会倒是 tini 下面的子程序无法结束,改成SIGTERM,dockerd 的重载信号是 SIGHUP:
lxc.signal.stop: SIGTERM lxc.signal.reboot: SIGHUP
为了保证容器停止的时候杀死容器相关的进程,例如:pct enter 101 进入容器后一些列操作,在容器关闭时,确保这些进程被杀死,添加一个停止钩子:
pct enter 101
lxc.hook.stop: sh -c 'kill $(pgrep -f "lxc-attach -n ${LXC_NAME}") 2> /dev/null'
/usr/share/lxc/config/
/var/lib/lxc/<CID>/config
include
/usr/share/lxc/config/common.seccomp
lxc.log.level: 0 lxc.log.file: /tmp/lxc-100.log
下载alpine 模板 第一次进入容器安装必要 docker apk add docker docker-cli tini
apk add docker docker-cli tini
# /etc/pve/lxc/100.conf #net0: name=eth0,bridge=vmbr0,firewall=1,gw=10.1.1.1,hwaddr=BC:24:11:8B:5F:E4,ip=10.1.1.201/24,type=veth #lxc.cgroup.cpu: /sys/fs/cgroup/cpu,cpuacct #lxc.cgroup.memory: /sys/fs/cgroup/memory cores: 20 memory: 81920 swap: 4096 #lxc.namespace.clone: mnt uts arch: amd64 hostname: CT0 nameserver: 10.1.1.1 ostype: alpine rootfs: local:101/vm-101-disk-0.raw,size=24G timezone: Asia/Shanghai lxc.signal.reboot: SIGHUP lxc.signal.stop: SIGTERM lxc.cgroup2.devices.allow: a lxc.log.level: 0 lxc.log.file: /tmp/lxc-100.log lxc.apparmor.profile: unconfined lxc.cap.drop: lxc.autodev: 1 lxc.hook.autodev: sh -c 'cat /proc/partitions | awk '"'"'{if ($1~/[0-9]+/) system("mknod -m 777 ${LXC_ROOTFS_MOUNT}/dev/"$4" b "$1" "$2)}'"'"'' lxc.mount.auto: proc:rw sys:rw cgroup-full:rw lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none rbind,optional,create=file lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none rbind,optional,create=file lxc.mount.entry: /dev/net/tun dev/net/tun none rbind,create=file lxc.mount.entry: tmp tmp tmpfs rw,nodev,relatime,mode=1777 0 0 lxc.mount.entry: /etc/fstab tmp/fstab none rbind,create=file lxc.mount.entry: /volumes volumes none rbind,create=dir lxc.mount.entry: /sys/fs/bpf sys/fs/bpf none rbind,create=dir lxc.hook.stop: sh -c 'kill $(pgrep -f "lxc-attach -n ${LXC_NAME}") 2> /dev/null' lxc.seccomp.profile: /root/unconfined.seccomp lxc.namespace.keep: user pid net ipc lxc.init.cmd: env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /sbin/tini-static -sg -- dockerd
pct start 100 # 启动容器 pct enter 100 # 进入容器 dpkg-reconfigure locales #添加 zh.CN_UTF8
vi /etc/default/grub # 修改 cmdline 如果是AMD处理器, 将intel_iommu改为iommu GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt initcall_blacklist=sysfb_init pci=assign-busses pcie_acs_override=downstream,multifunction"
https://www.jinbuguo.com/kernel/boot_parameters.html
打开 /etc/modules ,追加添加:
vfio vfio_iommu_type1 vfio_pci vfio_virqfd
lspci -nn | grep AMD 01:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Upstream Port of PCI Express Switch [1002:1478] (rev c7) 02:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Downstream Port of PCI Express Switch [1002:1479] 03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 23 [Radeon RX 6600/6600 XT/6600M] [1002:73ff] (rev c7) 03:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]
根据返回结果,得到 id, [1002:73ff],[1002:ab28]
echo "options vfio-pci ids=1002:73ff,1002:ab28" > /etc/modprobe.d/vfio.conf
update-grub update-initramfs -u -k all
https://github.com/strongtz/i915-sriov-dkms 更新内核后记得重新安装 dkms 内核模块
将 displaylink usb 端口通入虚拟机,win11 会自动安装驱动。这样 sriov 核显就可以输出画面了
https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pct_settings https://github.com/strongtz/i915-sriov-dkms
The text was updated successfully, but these errors were encountered:
No branches or pull requests
高权限 LXC 容器配置 --- 只运行 docker 的容器
创建一个基于CT 模板为alpine 的 LXC 容器,启动之后需要修改源和安装 docker
块设备
将设备挂载入容器的前提,必须对 cgroup2 进行设置,
lxc.cgroup2.devices.allow: b *:* rwm
,b 表示块设备,设备号可以使用ls -l /dev
或者lsblk
查看,: 表示所有设备号创建设备文件也可以使用
autodev hook
实现,这个脚本实现了所有块设备的创建。后续,容器使用过程中,例如硬盘重新分区,usb 等热插拔设备,想让容器能够获取到设备最新状态,可以运行下列命令:
字符设备
同样的,与块设备一样,只需对 cgroup2 进行设置
lxc.cgroup2.devices.allow: c *:* rwm
,c 表示字符设备,设备号可以使用ls -l /dev
查看,: 表示所有设备号*所有设备
** 可能会出现意想不到的问题 **
再进一步,如果要对所有设备进行直通,可以使用,
lxc.cgroup2.devices.alllow: a
表示允许所有设备,但是如何对所有文件挂载进入 lxc 容器的,同时,如果设备文件发生变化,例如硬盘重新分区,usb 等热插拔设备,需要让容器能够获取到,就需要一些小小的魔法,这里将/dev
目录挂载为 overlayfs 并挂入容器内部,这样,lxc 容器就能直接使用 /dev 内的内容了。网卡直通
默认情况下,pve 会给容器通过 veth 网桥来分配虚拟网卡,如果 pve 主机有多个网卡,可以将网卡直通入 lxc:
macvlan网卡
只有一张网卡的情况,使用 macvlan 会比 veth 带来更好的性能表现:
将 /volumes 及 fstab 挂入容器
挂载
/volumes
以及fstab
的目的是,计划通过编辑容器内的/tmp/fstab
来实现PVE宿主开机自动挂载到/volumes
目录中,使用rbind
参数使其,具有挂载传播性,即:宿主机挂载硬盘,在容器中也能看到。创建挂载的目录,同时为了保护 /meida 目录下的 disk* 目录,可以使用chattr修改权限
挂载硬盘
使用fstab
创建完目录之后,可以挂载硬盘,当然如果是新硬盘,要分区格式化
挂载完成所有硬盘之后,可以将相关挂载信息写入fstab,以便下次重启,自动挂载,这里写了一个小脚本来帮助填写
执行之后,会输出相应的配置,只要追加复制到 /etc/fstab 就行了
使用脚本
考虑到写入
fstab
后,如果硬盘出现问题或者硬盘拔出后,会在启动时报错,所以考虑在容器启动时执行用脚本挂载操作。而使用
mp0=/dev/sdaX...
则会导致每次重启容器都需要卸载和挂载,带来不必要的操作。同样创建完目录之后,可以挂载硬盘,当然如果是新硬盘,要分区格式化
挂载 proc sys cgroup tmpfs 等
权限设置
禁用 AppArmor 提升容器权限,lxc.cap.drop 空表示容器支持所有 Linux Capabilities 权限,进一步提升权限,可以使用 capsh --print 查看,可以使用smartctl 查看磁盘 S.M.A.R.T. 信息
使用部分宿主 namespaces
lxc 可以支持 clone/keep/share 等方式将宿主机的 namespaces 与容器共用。
可以使用
lxc.namespace.keep
lxc.namespace.clone
lxc.namespace.share.*
这三个参数进行设置,详情可以查看 man page。但是 pve 的 pct 配置文件并不支持者三个参数,可以使用下面这个补丁来解除限制:
信号
lxc 默认的 stop 信号是 SIGKILL,这会倒是 tini 下面的子程序无法结束,改成SIGTERM,dockerd 的重载信号是 SIGHUP:
STOP HOOK
为了保证容器停止的时候杀死容器相关的进程,例如:
pct enter 101
进入容器后一些列操作,在容器关闭时,确保这些进程被杀死,添加一个停止钩子:其他配置
/usr/share/lxc/config/
中找到 pve 自带模板的默认配置,如果要确定容器使用来哪个模板,可以在/var/lib/lxc/<CID>/config
中的include
中找到/usr/share/lxc/config/common.seccomp
中配置日志
整体配置文件
下载alpine 模板
第一次进入容器安装必要 docker
apk add docker docker-cli tini
中文终端 locales
PVE 虚拟机
独显直通
bios 相关设置
内核启动参数
相关参数含义
References
* 启动 VFIO 模块 (非必需,虚拟机直通时会自动加载相关模块)
打开 /etc/modules ,追加添加:
修改 vfio 配置文件,启用 audio
根据返回结果,得到 id, [1002:73ff],[1002:ab28]
更新 grub 和 initramfs
核显直通
intel gen11+ 核显 sriov
https://github.com/strongtz/i915-sriov-dkms
更新内核后记得重新安装 dkms 内核模块
使用 displaylink 作为显示器
将 displaylink usb 端口通入虚拟机,win11 会自动安装驱动。这样 sriov 核显就可以输出画面了
References
The text was updated successfully, but these errors were encountered: