LXC容器运行X Server(续2-端口转发)

上篇介绍了只读mount宿主/tmp/.X11-unix到vm1容器/var/lib/lxc/vm1/rootfs/tmp/.X11-unix,实现容器运行X桌面环境,并因只读,保护了宿主/tmp/.X11-unix不被容器破坏,但却因此容器的X Server没能创建套接字文件,导致某些应用如ssh的X11转发依赖套接字文件而在容器无法使用

socat是一强大的端口转发工具,可以实现套接字转发,就如ssh的X11转发,本篇就是实现socat转发X,使容器既能运行X桌面环境,又保持容器/var/lib/lxc/vm1/rootfs/tmp/.X11-unix可写

1.回顾上篇(https://blog.51cto.com/13752418/2461908)
宿主启动Xephyr创建了套接字文件(在/tmp/.X11-unix/下)和抽象unix域
只读mount宿主/tmp/.X11-unix/到容器/tmp/.X11-unix/,即宿主套接字文件共享给了容器
容器只能通过宿主套接字文件和宿主通信,无法通过宿主抽象unix域
容器启动Xephyr运行在宿主Xephyr之上(通过宿主套接字文件),并创建了容器抽象unix域,因只读/tmp/.X11-unix/所以容器无法创建套接字文件
容器的图形程序通过容器抽象unix域运行在容器Xephyr之上
而ssh的X11转发恰好只能通过套接字文件,无法通过抽象unix域

1)宿主

linlin@debian:~$ netstat -lp |grep X
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)
Active UNIX domain sockets (only servers)
unix  2      [ ACC ]     STREAM     LISTENING     19548    -                    @/tmp/.X11-unix/X0
unix  2      [ ACC ]     STREAM     LISTENING     19549    -                    /tmp/.X11-unix/X0
unix  2      [ ACC ]     STREAM     LISTENING     29044    Xephyr               /tmp/.X11-unix/X1
unix  2      [ ACC ]     STREAM     LISTENING     29043    Xephyr               @/tmp/.X11-unix/X1
linlin@debian:~$

X1为宿主Xephyr

2)容器

linlin@vm1:~$ ls -a /tmp |grep X*lock
.X30-lock
linlin@vm1:~$ ls   /tmp/.X11-unix
X0
X1
linlin@vm1:~$ netstat -lp |grep X
Active UNIX domain sockets (only servers)
unix  2      [ ACC ]     STREAM     LISTENING     29054    Xephyr              @/tmp/.X11-unix/X30
linlin@vm1:~$

X0、X1为宿主
X30为容器Xephyr,只有抽象unix域,没有套接字文件

2.在宿主编辑容器配置文件/var/lib/lxc/vm1/config
添加下面一行
lxc.mount.entry = /tmp/.X11-unix tmp/.X11-unix-host none bind,ro,optional,create=dir

与上篇同样只读mount宿主/tmp/.X11-unix,但容器里的路径变为tmp/.X11-unix-host,路径名随便取,只要不是tmp/.X11-unix
即容器里的原有/tmp/.X11-unix路径不要被mount --bind

3.宿主
普通用户运行下面命令

linlin@debian:~$ ls /tmp/.X11-unix/
X0
linlin@debian:~$

X0表示存在显示号0

运行Xephyr并新建显示号1
linlin@debian:~$ Xephyr :1

4.容器
1)安装socat
root@vm1:/# apt-get install socat

2)列出显示号

linlin@vm1:~$ ls /tmp/.X11-unix-host
X0  X1
linlin@vm1:~$

可见mount --bind后宿主的X0、X1

linlin@vm1:~$ ls -l /tmp/.X11-unix
(空)
linlin@vm1:~$ 

可见容器还没有显示号

3)将X1从/tmp/.X11-unix-host转发到路径/tmp/.X11-unix/下

linlin@vm1:~$ socat UNIX-LISTEN:/tmp/.X11-unix/X20,fork UNIX-CONNECT:/tmp/.X11-unix-host/X1&
linlin@vm1:~$ ls -l /tmp/.X11-unix
srwxr-xr-x 1 linlin linlin 0 3月  22 02:40 X20
linlin@vm1:~$ 

可见/tmp/.X11-unix/下已创建了套接字文件X20,即显示号X20(也即宿主的[Xephyr :1])

4)运行Xephyr
指定创建显示号30

linlin@vm1:~$ DISPLAY=:20 Xephyr :30 &
  458 pts/1    00:00:00 Xephyr
linlin@vm1:~$ ls -l /tmp/.X11-unix
srwxr-xr-x 1 linlin linlin 0 3月  22 02:40 X20
linlin@vm1:~$ netstat  |grep X
Active UNIX domain sockets (w/o servers)
unix  3      [ ]         STREAM     CONNECTED     321359   /tmp/.X11-unix/X20
linlin@vm1:~$ netstat -lp |grep X
Active UNIX domain sockets (only servers)
unix  2      [ ACC ]     STREAM     LISTENING     318282   451/socat            /tmp/.X11-unix/X20
linlin@vm1:~$ 

没见到X30

linlin@vm1:~$ DISPLAY=:30 xlogo
Can't open display: :30
linlin@vm1:~$ 

在X30运行图形程序失败,因为不存在显示号30

可见Xephyr虽然在运行,但没创建套接字文件X30,也没创建抽象unix域
也就是说,使用socat转发,Xephyr无法创建显示号X30

5)运行其它图形程序
linlin@vm1:~$ DISPLAY=:20 xlogo
这个图形程序在显示号X20运行正常
X20实际是宿主的X1,虽然容器中的图形程序可在[Xephyr :1]上正常运行,但我的目的是要运行完整的容器桌面环境,要在容器先运行一个X Server,图形程序在容器自己的X Server上运行

6)容器中用Xnest代替Xephyr,宿主仍用Xephyr
root@vm1:/# apt-get install xnest

指定创建显示号30,并在[:20]上运行
linlin@vm1:~$ DISPLAY=:20 Xnest :30 &
[2] 435
linlin@vm1:~$ ls -l /tmp/.X11-unix
srwxr-xr-x 1 linlin linlin 0 3月 22 03:11 X20
srwxrwxrwx 1 linlin linlin 0 3月 22 03:12 X30

linlin@vm1:~$ netstat -lp |grep X
Active UNIX domain sockets (only servers)
unix  2      [ ACC ]     STREAM     LISTENING     403819   435/Xnest            /tmp/.X11-unix/X30
unix  2      [ ACC ]     STREAM     LISTENING     403818   435/Xnest            @/tmp/.X11-unix/X30
unix  2      [ ACC ]     STREAM     LISTENING     401403   431/socat            /tmp/.X11-unix/X20
linlin@vm1:~$ 

Xnest成功创建了套接字文件X30,也创建了抽象unix域
linlin@vm1:~$ DISPLAY=:30 jwm &
在[Xnest :30]上运行图形程序正常
linlin@vm1:~$ exit
注销用户linlin,因是&后台运行,注销登录后Xnest、socat仍在运行的

7)登录管理器
由xdm来启动Xnest
将容器的/etc/X11/xdm/Xservers中
:0 local /usr/bin/X :0 vt7 -nolisten tcp
一行修改为
:30 local /usr/bin/Xnest -geometry 800x600+0+0 :30

其中:30是指定Xnest创建的显示号,屏幕尺寸800x600

root@vm1:~# DISPLAY=:20 xdm -nodaemon &

已成功启动xdm对话框.运行xdm指定的环境变量显示号是20,但这个显示号20应该主要是传递到Xnest.Xnest运行在[:20]之上,即socat转发的宿主[Xephyr :1]

参考宿主xdm启动/usr/bin/X,宿主xdm对话框必定在其/usr/bin/X的显示号之上.容器xdm对话框应该运行在容器[Xnest :30]之上,而非环境变量[:20]

root@vm1:~# ps -e
   进程号
...
    117 pts/2    00:00:00 bash
    125 pts/4    00:00:00 socat
    126 pts/5    00:00:00 xdm
    129 ?        00:00:00 Xnest
    130 pts/4    00:00:00 socat
    133 ?        00:00:00 xdm
    291 pts/2    00:00:00 ps
root@vm1:~#

socat有两个进程,分别125和130进程号;xdm也有两个进程,分别126和133进程号,126号xdm运行在pts/5,133号xdm是守护进程
从上面进程号顺序体现了命令进程启动的先后次序,可见在终端运行xdm(126)命令启动了Xnest,随Xnest之后启动的xdm(133)也应该是由xdm(126)启动的
因此应该xdm(133)才是运行在[Xnest :30]之上的xdm登录对话框

root@vm1:~# netstat -lp |grep X
Active UNIX domain sockets (only servers)                进程号/命令名
unix  2      [ ACC ]     STREAM     LISTENING     127087   129/Xnest            @/tmp/.X11-unix/X30
unix  2      [ ACC ]     STREAM     LISTENING     127085   125/socat            /tmp/.X11-unix/X20
unix  2      [ ACC ]     STREAM     LISTENING     127088   129/Xnest            /tmp/.X11-unix/X30
root@vm1:~# netstat -p |grep X
Active UNIX domain sockets (w/o servers)
unix  3      [ ]         STREAM     CONNECTED     126180   -                    /tmp/.X11-unix/X20
unix  3      [ ]         STREAM     CONNECTED     126183   129/Xnest            @/tmp/.X11-unix/X30
unix  3      [ ]         STREAM     CONNECTED     124810   130/socat            /tmp/.X11-unix/X20
unix  3      [ ]         STREAM     CONNECTED     127090   129/Xnest            
unix  3      [ ]         STREAM     CONNECTED     124817   129/Xnest            @/tmp/.X11-unix/X30
root@vm1:~# 

安装lsof,查看打开文件
root@vm1:~# apt-get install lsof

root@vm1:~# lsof -U |grep xdm 
         进程号           描述符
xdm       133       root    4u  unix 0x0000000050f42d76      0t0 124814 type=STREAM
xdm       133       root    5u  unix 0x000000005a6b92b7      0t0 126189 type=STREAM
root@vm1:~# 

查看到xdm(133,守护进程)使用了unix域进程间通信,没发现xdm(126,命令行)使用unix域

root@vm1:~# lsof /tmp/.X11-unix/X30
(空)
root@vm1:~#
查看套接字文件X30打开情况,结果为空,不懂

通过netstat和lsof还是无法看出xdm(133)对话框在[:20]还是[Xnest :30]之上,我也找不出什么方法途径可查看那些进程打开了套接字文件,所以我只能根据进程启动顺序猜测xdm(133)对话框运行在[Xnest :30]之上

root@vm1:~# kill -9 133
杀死xdm(133)进程,可见又立即重启xdm对话框,125和126号进程保持不动,其它杀掉重启了

root@vm1:~# ps -e
    PID TTY          TIME CMD
...
    117 pts/2    00:00:00 bash
    125 pts/4    00:00:00 socat
    126 pts/5    00:00:00 xdm
        以下新的进程
    331 ?        00:00:00 Xnest  
    332 pts/4    00:00:00 socat
    335 ?        00:00:00 xdm
    343 pts/2    00:00:00 ps
root@vm1:~# 

每次的桌面会话注销/登录,伴随着重新创建新的守护进程xdm

5.小结
1)只读mount宿主/tmp/.X11-unix/到容器/tmp/.X11-unix-host/
2)容器/tmp/.X11-unix/保持原样可读写
3)容器使用socat将X从/tmp/.X11-unix-host/转发到/tmp/.X11-unix/
4)容器使用Xnest代替Xephyr

( 附:LXC容器图形前端 fglxc-ver0.2.1.zip 源代码 下载地址 http://u.163.com/m8BXHXFWv 提取码: i1bG8PwH )

猜你喜欢

转载自blog.51cto.com/13752418/2603398