リモートのDockerで実行したGUIアプリをSSHでX11Forwardingする
権限まわりで数時間手間取ったので、それを解決したTips。
実現したいこと
SSHで接続したマシンのDockerコンテナ内でX11クライアントアプリ(e.g. xeyes
)を実行して、ローカルマシンのディスプレイに表示する。
その時に、SSHポートフォワーディングを利用してローカルとリモートでX11プロトコル通信をする。
X Window System
ネットワークを通じてGUI環境を構築するためのプロトコルおよびアプリケーション。
UNIXと関わりの深い技術らしいが、専門ではないので詳しくは知らない。 初めてX11プロトコル通信に成功すると感動する(実体験)。
事前準備
ローカルマシンでX11サーバを起動しておく
Google it♡
リモートマシンのsshdでX11Forwardingを許可する
デフォルトで許可されているが、念のため/etc/ssh/sshd_config
を確認する。
... X11Forwarding yes X11DisplayOffset 10 X11UseLocalhost yes
sshdを再起動して変更の反映
$ sudo systemctl restart sshd
ローカルマシンの環境変数DISPLAYを設定する
これを忘れていて軽く詰まった。
# DISPLAY=[端末のアドレス]:[ディスプレイ番号].[スクリーン番号] $ export DISPLAY=localhost:0.0
X11 - DISPLAY (environment variable) | X11 | Datacadamia - Data and Co (accessed on 2022/04/30)
リモートマシンでアプリケーションを動かす
SSHでリモートマシンへ接続する
-X
オプションまたは-Y
オプションでX11Forwardingをssh側でいろいろ処理してくれる。
-X
と-Y
の違いはTrustedかUnTrustedかであるそうだが、詳しくは知らない。
$ ssh -X ... # または $ ssh -Y ...
先ほどの設定通りならばリモートマシンの環境変数DISPLAYが次のように設定されているはず。
$ echo $DISPLAY localhost:10.0
以降はリモートマシンでの作業である。
Dockerfile
今回使用するイメージ。
ユーザーはroot
を使用する。
FROM ubuntu:latest RUN apt-get update \ && apt-get install -y x11-apps USER root CMD ["/bin/bash"]
適当なタグでビルドしておく。
$ docker build -t x11-test .
コンテナを作成する
docker-compose
でも良いのだが、今回はshellスクリプトx11-test.sh
を書くことにする。
#! /bin/bash docker run \ -it \ --rm \ -e DISPLAY=$DISPLAY \ --net host \ --mount type=bind,src=$HOME/.Xauthority,dst=/root/.Xauthority.copy \ # ここがポイント x11-test \ /bin/bash -c " \ cp /root/.Xauthoriy.copy /root/.Xauthority; \ # ここがポイント2 chown root:root /root/.Xauthority; \ # ここがポイント3 xeyes \ "
やっていることはSSHでポートフォワーディングしているDockerホストのネットワークを利用して、コンテナ内部からX11クライアントアプリをローカルマシンのX11サーバアプリに繋いでいるだけ。
その際の認証情報として$HOME/.Xauthority
が必要であるが、これをコンテナにそのままマウントしてしまうとファイルの所有者が異なるため、x11 authentication failed for x11 forwarding
と怒られてしまう。
そこで一旦/root/.Xauthority.copy
へとマウントしてから/root/.Xauthority
へコピーして、ファイルの所有者を適切なものに変更している。
手間を惜しんでマウントした.Xauthority
の所有者を変更してしまうとDockerホストのファイルもroot権限になってしまい、面倒なことになる。
$ /bin/bash x11-test.sh
例の目がディスプレイに表示されれば成功。
おわりに
.Xauthority
の所有者が原因でエラーが出ていることを特定できたとき、最初に考えたのがコンテナのユーザ(uid, gid)をDockerホストのユーザと一致させる案だったが移植性を考慮した実装が面倒くさすぎて投げた。
「コピーして所有者変えたらいけるんじゃね?」と実行してみたら上手くいったのでここに記す。
記事内容を実行してみたらxeyes
においては.Xauthority
の所有者は関係なさそうである。
自分はchromium
を実行した際にエラーにぶち当たったのでアプリケーションに依存するのかもしれない。
X Window Systemに慣れていない場合は、
- ローカルDockerのコンテナで試してみる
- リモートでDockerを使わずにxeyesを実行する
と別々に練習すると上手くいくかもしれない。