容易上手的LXD容器和虚拟X server

Share on:

Overview

Linux有容器技术LXC,LXD对LXC进行了封装。与Docker类似,但LXC容器比Docker容器完整,且不像Docker是一次性容器设计运行结束后即销毁实例。使用LXD操作容器,体验介于Docker与虚拟机之间。(其实LXD不只提供封装LXC容器的功能,还提供封装虚拟机)

开始使用LXD——初始设置

  1. 从自己的发行版仓库安装LXD。LXD与Docker一样有一个守护进程lxd,因此有

    1sudo systemctl enable/disable/start/stop lxd
    

    如果用systemctl停止lxd时,仍有正在运行的容器,那些容器不会被停止。所以应该先停止所有容器,再systemctl stop

    lxd是守护进程,而平时操作LXD则是用lxc命令(此lxc非属于LXC容器,是LXD的客户端的意思)

  2. 安装LXD后自动创建lxd用户组,我们手动把自己的日常用户添加进这个组里:

    1usermod -aG lxd <username>
    
  3. 添加清华LXC镜像(下文都用这个tuna-images源):

    1lxc remote add tuna-images https://mirrors.tuna.tsinghua.edu.cn/lxc-images/ --protocol=simplestreams --public
    

    若想在连接镜像时使用代理:

    1lxc config set core.proxy_http http://ip:port
    2lxc config set core.proxy_https http://ip:port
    3lxc config set core.proxy_ignore_hosts image-server.local 
    
  4. /etc/subuid/etc/subgid都写

    11000:1000000:65536
    2root:1000000:65536
    3lxd:1000000:65536
    

    让容器进程运行时,宿主看到的容器进程所属UID以一百万算起 (外一百万=内0)。且容器的rootfs/下的文件在宿主机看来UID、GID也都是一样map过的。这种叫非特权容器,比特权容器安全。

  5. 初始化LXD。运行

    1sudo lxd init
    

    交互问答式的。

    • 其中有一个项让我们选择储存方式,我们自用选最简单的dir方式就可以,简单实用(这样容器内文件可以直接访问/var/lib/lxd/storage-pools/default/containers/容器名/rootfs/查看修改)。
  6. (可选)缓存与自动刷新相关设置

    1lxc config set images.remote_cache_expiry 30
    2lxc config set images.auto_update_interval 24
    3lxc config set images.auto_update_cached false 
    
  7. 重启

  8. 若宿主机有防火墙,可能需要手动把lxdbr0加入白名单,以使容器能够联网和与宿主机网络通信

使用LXD的常用操作

  • 查看网络源目前可下载的镜像

    1lxc image list tuna-images:
    
  • 查看本地已缓存镜像

    1lxc image list local:
    
  • 下载镜像到本地缓存

1    lxc image copy ubuntu:14.04 local:
  • 使用镜像创建并运行容器

    1lxc launch tuna-images:发布版/版本/架构 容器名
    

    发布版/版本/架构也可以用它的一串十六进制数字id替代表示)

  • 运行或停止容器

    1lxc start 容器名
    2
    3lxc stop [-f] 容器名
    
  • 获得容器的bash shell

    1lxc exec 容器名 bash
    

    上面这个是non-login shell。它支持stdin传入,如:

    1cat 宿主机上的某shell脚本 | lxc exec 容器名 bash -
    

    (可选)在容器内,用passwd设置root密码。内账户有密码后,可登录容器获得login shell:

    1lxc console 容器名
    
  • 挂载主机路径到容器

    1lxc 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

  • 查看挂载

    1lxc config device show <容器名>
    
  • 手动带UID、GID map的挂载

    前面说到,以非特权方式运行容器,UID、GID是map过的。如果内核不支持shiftfs,可以考虑一些workaround方案,用其他方式来做map(选其中一个):

    • bindfs:

      1bindfs -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

    1apt-get install xvfb
    
    1Xvfb -ac :3 [-listen tcp]  [-screen 0 1280x1024x24 ]
    

    (它可能不会有任何输出)

  • Xdummy

    • 第一种情况:需要编译
    1apt-get install x11vnc xserver-xorg-video-dummy gcc
    
    1Xdummy -install 
    

    Xdummy是一个脚本,这一步实际上是用cc编译一个.so出来,准备结合LD_PRELOAD运行X server。Xdummy也可以调用X

    启动:

    1Xdummy :3  [-listen tcp]
    

    若报错 dlsym No such file ,则在上一步编译时,加一个环境变量 CFLAGS="-ldl"

    • 第二种情况:不需要编译

      这种情况下可以没有Xdummy这个脚本文件。

      创建/tmp/dummy.conf写入:

       1Section "Monitor"
       2  Identifier "Monitor0"
       3  HorizSync 28.0-80.0
       4  VertRefresh 48.0-75.0
       5  # https://arachnoid.com/modelines/
       6  # 1920x1080 @ 60.00 Hz (GTF) hsync: 67.08 kHz; pclk: 172.80 MHz
       7  # Modeline "1920x1080_60.00" 172.80 1920 2040 2248 2576 1080 1081 1084 1118 -HSync +Vsync
       8  Modeline "1280x720_60.00"   74.50  1280 1344 1472 1664  720 723 728 748 -hsync +vsync
       9EndSection
      10
      11Section "Device"
      12  Identifier "Card0"
      13  Driver "dummy"
      14  VideoRam 256000
      15EndSection
      16
      17Section "Screen"
      18  DefaultDepth 24
      19  Identifier "Screen0"
      20  Device "Card0"
      21  Monitor "Monitor0"
      22  SubSection "Display"
      23    Depth 24
      24    Modes "1280x720_60.00"
      25  EndSubSection
      26EndSection
      

      然后运行:

      1X -config /tmp/dummy.conf :3 -listen tcp
      

启动了虚拟的X server在:3后,就可以

1env DISPLAY=:3 某GUI程序

也可以把Xvfb运行在宿主机上。这样要在容器内设定export DISPLAY=宿主机IP:3

如果X server与client(client即那些GUI程序)不是运行在一个系统上的,虚拟X server那边则需要执行:

1xhost +<另一系统的IP>

通过shell对虚拟X server操作和截图

1apt-get install xdotool xwd scrot x11vnc

其中:

  • xdotool,模拟键盘和鼠标动作

  • x11vnc,VNC服务器,把X server内容和操作提供给VNC客户端

  • scrot,截图工具(推荐)

  • xwd,截图工具(不推荐)

模拟鼠标操作

容器内运行xdotool

1env DISPLAY=:3 xdotool getmouselocation
2env DISPLAY=:3 xdotool mousemove <x> <y>
3env DISPLAY=:3 xdotool click 1    # (1是左键)

VNC

容器内运行VNC服务

1x11vnc -display :3 -N -forever -shared -reopen [-passwd 123456] -desktop 1

宿主机可用Remmina连接容器IP:5903(因为容器内用了:3这个DISPLAY,所以默认的x11vnc服务端口是5903),密码为上面设置的123456

注意在Redmina中挥动鼠标可能会使截图中的鼠标隐藏。用xdotool mousemove可恢复

截图

在容器内运行CLI截图工具。

xwd(不推荐):

1xwd -display :3 -root -out /media/share-from-host/shot.xwd
2
3(主机中或容器中) convert shot.xwd shot.png

上面的convert是ImageMagick的命令

scrot(推荐):

1env DISPLAY=:3 scrot /media/share-from-host/shot.png -p   # (-p : 截图包括鼠标)

(如果在CI中,截图后要上传artifacts)

也可以运行simplescreenrecorder或ffmpeg等对虚拟X server录屏(录屏工具与虚拟X server要运行在同一系统上)。

本博客文章皆属原创(除特别标明外)。 未联系作者获得同意前,不可转载。
All articles are original (except for those specially claimed) and copyrighted. Copying without permission is forbidden.

打赏作者

写作不易,感谢支持! 扫个码吧~