上篇介绍了只读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并新建显示号1linlin@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 )