Docker Desktop for Mac上のX ClientをホストのXQuartz(X Window Server)で表示する

$ docker -v
Docker version 20.10.0, build 7287ab3

$ brew -v
Homebrew 2.6.2
Homebrew/homebrew-core (git revision ce927; last commit 2020-12-19)
Homebrew/homebrew-cask (git revision eb977; last commit 2020-12-19)

$ brew info xquartz
xquartz: 2.7.11 (auto_updates)
https://www.xquartz.org/
/usr/local/Caskroom/xquartz/2.7.11 (74.6MB)
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/xquartz.rb
==> Name
XQuartz
==> Description
Open-source version of the X.Org X Window System
  • Docker Desktop for Mac 3.0.2 (50996)
  • macOS Catalina Version 10.15.7

XQuartzのインストール(HomebrewとHomebrew Cask)

現在はbrew caskコマンドは非推奨で、brewだけでOK(あるいは--caskオプションをつける)。 XQuartzの場合は--caskをつけなくても内部で勝手にbrew caskとしてインストールしてくれた。 Homebrew CaskというのはGUIアプリケーション向けのHomebrewの拡張らしいが、Homebrewと何が違うのかわからん。

Warning: Calling brew cask install is deprecated! Use brew install [--cask] instead.

Homebrewは、開発元からソースコードが配布されていて、そのコンパイル済みのバイナリ(またはソースダウンロード+自動ローカルビルド)を提供するもので、 Homebrew Caskは、*.dmgが配布されていてマウントして*.app/Applicationsにコピーする操作(実際には/usr/local/Caskroomにインストールする)のを自動化する、というものなのだろうか? --caskを明示するのは両方に登録されていてもCaskを優先するみたいな指定なのか? XQuartzの場合は--caskを付けなくてもCaskとしてインストールされた。

# brew install xquartz # これでもよさそう
brew install --cask xquartz

XQuartz.appを起動する。 シェルに環境変数DISPLAYが設定される(/private/tmp/com.apple.launchd.***/org.macosforge.xquartz:0のような値)。

XQuartzと合わせて導入されるxhostやxeyesにパスが通っていないので、/usr/X11/binにパスを通しておく。

# bashの場合:~/.bash_profile
export PATH=/usr/X11/bin:$PATH

起動確認。

xeyes

また、XQuartzのXQuartz > Preferences > Security > Allow connections from network clientsにチェックを入れる。 Dockerからアクセスするために必要。 また、この設定はXQuartzを再起動しないと反映されないので、一度XQuartzをQuitして起動しなおす。

テスト用Dockerイメージ

FROM alpine:3

RUN apk --no-cache add xeyes

CMD ["/usr/bin/xeyes"]
docker build . -t xeyes

確認:Docker Desktop for MacのDNS設定

以下のようなdocker pullに失敗する事象のため、Docker daemonのDNS設定を変更していた。 具体的には、Docker Desktop for Macのタスクバーアイコン > Preferences > Docker EngineのJSON設定欄に "dns": [ "primary dns address", "secondary dns adderss" ]のように設定を書き足して解決していた。

failed to solve with frontend dockerfile.v0: 
failed to create LLB definition: 
failed to authorize: 
rpc error: code = Unknown desc = failed to fetch oauth token: 
Get https://auth.docker.io/token?scope=repository%3Alibrary%2Fubuntu%3Apull&service=registry.docker.io: 
dial tcp 54.236.131.166:443: i/o timeout

この状態では、以下のhost.docker.internalを使う方法・hostnameを使う方法が動作せず、この設定は削除する必要があった。 なお最初に起きていた事象は、ネットワークのファイアウォールによってOP53B(DNSブロック)されていたのが原因と思われるが、 この設定を削除したとき、同様のネットワークで事象は復活しなかった(ネットワークの切り替え直後だったために起きていた一時的な問題?)。

host.docker.internalを使う方法(旧 docker.for.mac.localhost, docker.for.mac.host.internal)

この方法がシンプルで安全なように思われた。 以下は、X Serverのすべてのアクセス制限を復活させたのち、localhostからのアクセスのみを許可した状態でxeyesをDocker上で起動する。

xhost -
xhost + localhost

docker run --rm -e DISPLAY=host.docker.internal:0 xeyes

hostnameを使う+~/.Xauthorityを共有する方法

hostnameを使う+/tmp/.X11-unixを共有する方法

プライベートIPを使う方法

socatを使う方法(UnixソケットをTCPにリレーする方法)

SSH X11 Forwardingを使う方法