容易上手的LXD容器和虚拟X server
Linux有容器技术LXC,LXD对LXC进行了封装。与Docker类似,但LXC容器比Docker容器完整,且不像Docker是一次性容器设计运行结束后即销毁实例。使用LXD操作容器,体验介于Docker与虚拟机之间。(其实LXD不只提供封装LXC容器的功能,还提供封装虚拟机)
开始使用LXD——初始设置
-
从自己的发行版仓库安装LXD。LXD与Docker一样有一个守护进程
lxd
,因此有sudo systemctl enable/disable/start/stop lxd
如果用
systemctl
停止lxd时,仍有正在运行的容器,那些容器不会被停止。所以应该先停止所有容器,再systemctl stop
lxd
是守护进程,而平时操作LXD则是用lxc
命令(此lxc非属于LXC容器,是LXD的客户端的意思) -
安装LXD后自动创建
lxd
用户组,我们手动把自己的日常用户添加进这个组里:usermod -aG lxd <username>
-
添加清华LXC镜像(下文都用这个
tuna-images
源):lxc remote add tuna-images https://mirrors.tuna.tsinghua.edu.cn/lxc-images/ --protocol=simplestreams --public
若想在连接镜像时使用代理:
lxc config set core.proxy_http http://ip:port lxc config set core.proxy_https http://ip:port lxc config set core.proxy_ignore_hosts image-server.local
-
/etc/subuid
和/etc/subgid
都写1000:1000000:65536 root:1000000:65536 lxd:1000000:65536
让容器进程运行时,宿主看到的容器进程所属UID以一百万算起 (外一百万=内0)。且容器的
rootfs/
下的文件在宿主机看来UID、GID也都是一样map过的。这种叫非特权容器,比特权容器安全。 -
初始化LXD。运行
sudo lxd init
交互问答式的。
- 其中有一个项让我们选择储存方式,我们自用选最简单的
dir
方式就可以,简单实用(这样容器内文件可以直接访问/var/lib/lxd/storage-pools/default/containers/容器名/rootfs/
查看修改)。
- 其中有一个项让我们选择储存方式,我们自用选最简单的
-
(可选)缓存与自动刷新相关设置
lxc config set images.remote_cache_expiry 30 lxc config set images.auto_update_interval 24 lxc config set images.auto_update_cached false
-
重启
-
若宿主机有防火墙,可能需要手动把
lxdbr0
加入白名单,以使容器能够联网和与宿主机网络通信
使用LXD的常用操作
-
查看网络源目前可下载的镜像
lxc image list tuna-images:
-
查看本地已缓存镜像
lxc image list local:
-
下载镜像到本地缓存
lxc image copy ubuntu:14.04 local:
-
使用镜像创建并运行容器
lxc launch tuna-images:发布版/版本/架构 容器名
(
发布版/版本/架构
也可以用它的一串十六进制数字id替代表示) -
运行或停止容器
lxc start 容器名 lxc stop [-f] 容器名
-
获得容器的bash shell
lxc exec 容器名 bash
上面这个是non-login shell。它支持stdin传入,如:
cat 宿主机上的某shell脚本 | lxc exec 容器名 bash -
(可选)在容器内,用
passwd
设置root密码。内账户有密码后,可登录容器获得login shell:lxc console 容器名
-
挂载主机路径到容器
lxc config|profile device add <容器名|profile名> share-from-host(设备名) disk source=/tmp/share-to-lxd/ path=/media/share-from-host [shift=true]
shift=true
启用指非特权容器需要的UID、GID map。这个要求内核支持shiftfs。若无,非特权容器中看到的宿主机共享进去的文件都是
nobody:nobody
的,而主机中看到的容器内创建的文件都是1000000:1000000
。 -
查看挂载
lxc config device show <容器名>
-
手动带UID、GID map的挂载
前面说到,以非特权方式运行容器,UID、GID是map过的。如果内核不支持shiftfs,可以考虑一些workaround方案,用其他方式来做map(选其中一个):
-
bindfs:
bindfs -u 1000000 -g 1000000 --create-for-user=1000 --create-for-group=1000 /something-on-host /tmp/share-to-lxd/subdir
(注意:这样mount中套mount,有时有看不见的可能,有时要先启动容器,进入了share文件夹,再从主机中bindfs)
-
fuse-overlayfs
-
虚拟X server
容器镜像一般都不会带有GUI相关内容的,若想在容器内运行GUI程序,除了安装相应的包外,还需要一个X server。可以把宿主机的X server共享给容器用,但这需要处理好X授权,且安全性低些。可以在容器内运行虚拟的X server,可以通过截图、VNC、录屏方式查看和操作这个虚拟X server,这些方法在CI自动化测试时也有用。
虚拟的X server有:
- Xvfb
- Xdummy
Xdummy更晩出现,声称比Xvfb功能更多。选择其中的一个使用
启动虚拟X server
二个中选一
-
Xvfb
apt-get install xvfb
Xvfb -ac :3 [-listen tcp] [-screen 0 1280x1024x24 ]
(它可能不会有任何输出)
-
Xdummy
- 第一种情况:需要编译
apt-get install x11vnc xserver-xorg-video-dummy gcc
Xdummy -install
Xdummy
是一个脚本,这一步实际上是用cc
编译一个.so
出来,准备结合LD_PRELOAD
运行X server。Xdummy
也可以调用X
。启动:
Xdummy :3 [-listen tcp]
若报错 dlsym No such file ,则在上一步编译时,加一个环境变量
CFLAGS="-ldl"
-
第二种情况:不需要编译
这种情况下可以没有
Xdummy
这个脚本文件。创建
/tmp/dummy.conf
写入:Section "Monitor" Identifier "Monitor0" HorizSync 28.0-80.0 VertRefresh 48.0-75.0 # https://arachnoid.com/modelines/ # 1920x1080 @ 60.00 Hz (GTF) hsync: 67.08 kHz; pclk: 172.80 MHz # Modeline "1920x1080_60.00" 172.80 1920 2040 2248 2576 1080 1081 1084 1118 -HSync +Vsync Modeline "1280x720_60.00" 74.50 1280 1344 1472 1664 720 723 728 748 -hsync +vsync EndSection Section "Device" Identifier "Card0" Driver "dummy" VideoRam 256000 EndSection Section "Screen" DefaultDepth 24 Identifier "Screen0" Device "Card0" Monitor "Monitor0" SubSection "Display" Depth 24 Modes "1280x720_60.00" EndSubSection EndSection
然后运行:
X -config /tmp/dummy.conf :3 -listen tcp
启动了虚拟的X server在:3
后,就可以
env DISPLAY=:3 某GUI程序
也可以把Xvfb运行在宿主机上。这样要在容器内设定
export DISPLAY=宿主机IP:3
如果X server与client(client即那些GUI程序)不是运行在一个系统上的,虚拟X server那边则需要执行:
xhost +<另一系统的IP>
通过shell对虚拟X server操作和截图
apt-get install xdotool xwd scrot x11vnc
其中:
-
xdotool,模拟键盘和鼠标动作
-
x11vnc,VNC服务器,把X server内容和操作提供给VNC客户端
-
scrot,截图工具(推荐)
-
xwd,截图工具(不推荐)
模拟鼠标操作
容器内运行xdotool
env DISPLAY=:3 xdotool getmouselocation
env DISPLAY=:3 xdotool mousemove <x> <y>
env DISPLAY=:3 xdotool click 1 # (1是左键)
VNC
容器内运行VNC服务
x11vnc -display :3 -N -forever -shared -reopen [-passwd 123456] -desktop 1
宿主机可用Remmina连接容器IP:5903
(因为容器内用了:3
这个DISPLAY,所以默认的x11vnc服务端口是5903),密码为上面设置的123456
注意在Redmina中挥动鼠标可能会使截图中的鼠标隐藏。用xdotool mousemove可恢复
截图
在容器内运行CLI截图工具。
xwd(不推荐):
xwd -display :3 -root -out /media/share-from-host/shot.xwd
(主机中或容器中) convert shot.xwd shot.png
上面的convert是ImageMagick的命令
scrot(推荐):
env DISPLAY=:3 scrot /media/share-from-host/shot.png -p # (-p : 截图包括鼠标)
(如果在CI中,截图后要上传artifacts)
也可以运行simplescreenrecorder或ffmpeg等对虚拟X server录屏(录屏工具与虚拟X server要运行在同一系统上)。
关注一下
📺 Bilibili 收集有趣科技 和发布原创视频 | 🖥️ Github 有用的和没用的开源项目代码
玩而后赏
子曰,玩而予赏,善莫大焉?
又曰,玩而不赏,良心安焉?
写作不易,感谢支持!
虽然,小小玩意,不足挂齿;
亦是,卅年老刀,献丑于此。
其实,多赏非求,少许亦可。
进者,参观主页,玩物更多。
未联系作者获得同意前,不可转载
转载必须附上源地址,并连我博客上的宣传内容一并转载