我想从远程机器运行容器化的 GUI 应用程序。
我不想通过向容器添加 ssh 主机来解决这个问题,因为
- 我已经可以通过 SSH 访问主机
- 它增加了不必要的开销
- 这使得容器无法在远程和本地使用之间移植
我已经可以在主机上成功运行 GUI 应用程序,但无法在容器内运行。以下是我到目前为止采取的步骤:
主持人
xauth +
(不是长期的,但有助于消除可能出现的问题)docker-user
通过命名空间功能,主机上的 uid 为 501000 ==docker-user
容器中的 uid 为 1000.Xauthority
文件已复制到docker-user
主文件夹
Dockerfile
- 基于高山
- 安装
xauth
并进行测试,xterm
docker-user
使用适当的 uid/gid创建
docker-compose
DISPLAY
转发的环境变量/home/docker-user/:/home/docker-user/:ro
提供.Xauthority
cookie的数量/tmp/.X11-unix:/tmp/.X11-unix:ro
提供 X11 套接字访问的卷- 运行命令
su - docker-user -c "export DISPLAY=$DISPLAY && xterm"
su
曾经作为docker-user
DISPLAY
转发到su
上下文中
不幸的是,这还不够。虽然主机操作系统上的 xterm 可以毫无问题地连接到我的本地 X 服务器,但容器中的 xterm 却显示Xt error: Can't open display: localhost:10.0
。
我已确认“localhost:10.0”是正确的,localhost 存在于容器中/etc/hosts
,并且 cookie 和套接字正在以正确的权限通过。
还有什么可能出错?
答案1
看起来你正在做我正在做的所有事情,除了你在创建容器时共享 .Xauthority。这意味着如果你在创建容器后 ssh -X 进入你的机器,.Xauthority 将不再有效。你不能从另一个终端 ssh -X 进入同一台机器,然后返回并使用 .Xauthority,ssh -X 每次都会为最新的终端更改 .Xauthority。我只能通过每次 ssh -X 进入我的机器并尝试与我的容器共享屏幕时复制 .Xauthority 来使其工作。
注意:我之所以共享设备和机器 ID,是因为我正在转发网络摄像头输出
1.创建容器并告诉xhost允许从容器id转发:
sudo docker run -it -d \
--net=host \
--env="DISPLAY" \
--env="QT_X11_NO_MITSHM=1" \
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
--device="/dev/video0:/dev/video0" \
--volume="/path/to/your/sharedDockerFiles:/root/sharedDockerFiles" \
--volume="/etc/machine-id:/etc/machine-id" \
yourdockerrepo/image:tag \
bash
export containerId=$(docker ps -l -q)
sudo xhost +local:`sudo docker inspect --format='{{ .Config.Hostname }}' $containerId`
sudo docker start $containerId
2.将 .Xauthority 从主机主目录复制到 sharedDockerFiles 目录:
sudo cp ~/.Xauthority /path/to/your/sharedDockerFiles
3.启动并连接你的容器
4.将共享文件夹中的 .Xauthority 复制到容器主目录中
sudo cp /root/sharedDockerFiles/.Xauthority ~/
5.(必要一次):编辑 Host * 下的容器的 /etc/ssh/ssh_config 以包含:
ForwardX11 yes
X11Forwarding yes
6.重新启动容器并重新连接并运行 GUI 应用程序
7.如果仍然有问题,请确保容器中的 $DISPLAY 变量与主机的相同
echo $DISPLAY #do this in the container
exit
echo $DISPLAY #do this in the host, should be the same as container's
#if they aren't equal, start container and:
export DISPLAY= #put the output of your host's $DISPLAY variable here
答案2
在使用 GUI 之前,在 ssh 会话开始时将 .Xauthority 复制到容器中:
sudo docker exec -i container_name bash -c 'cat > ~/.Xauthority' < ~/.Xauthority
然后,如果使用“docker exec”,则可以传递 DISPLAY。例如打开新的 bash:
sudo docker exec -it --env="DISPLAY" container_name bash
另外 2 个可能导致错误的原因:(除了接受的答案)
基本的:您在容器中没有 ssh 服务器或 xauth(对于 ubuntu,运行“apt install openssh-server xauth”)
鬼鬼祟祟的:如果您的容器主机名与主机上的不同(例如通过“docker run”中的-h badge设置),您将收到错误,并且您必须处理它(例如设置相同的主机名或将 cookie 添加到 xauth)
答案3
让我们使用 --net=host 选项启动 docker。它使容器能够看到与主机相同的网络堆栈。
例如,
docker run --net=host --rm -ti -u myid -e DISPLAY="$DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix image:tag BINARY