xvfbで、ヘッドレスのdockerコンテナ内でSeleniumを実行できるようにはなったのですが、ホントに実行されているのか、まだ信用できない....!
せっかくなので、dockerコンテナ内でSeleniumの実行画面を、Mac側のXに飛ばせないかと思ったところ。
いろいろ時間が解決してくれているようで、この手のノウハウがあちこちに落ちておりました。
- Docker Issue: how to use -e DISPLAY flag on osx? #8710
- How to get a GUI to a Docker Container on OS X
- Qiita: macでdockerからGUIアプリを立ち上げる
ちょっとハマったところはありましたが、前回使ったものと同じテストを、Mac側に表示させて実施できましたので、そのメモになります。
実際なにをやっているの?
実際なにをやっているか良くわかってなかったので、学習も兼ねて書いていきます。
流れとしては、以下の通り。
- socat というコマンドラインツールを追加
- Xquartzをインストール
- デフォルトでは入っていない && brew installの標準には入ってないので、caskを利用してインストール
- X11の環境を整えたあとで、socat TCP-LISTEN.... で、ポート6000で待ち受け(X用のポート)
- docker runの時に環境変数 (DISPLAY) を渡して、GUIアプリを起動
- コンテナ側で起動したアプリは、MacのXサーバに描画してもらう
Macのターミナル上での処理は、『macでdockerからGUIアプリを立ち上げる』 の記事の通り、このようになります。
brew install socat
brew install caskroom/cask/brew-cask
brew cask install xquartz
open -a XQuartz
# socatを起動すると、そのまま待ち状態になるので、別ターミナルへ
socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
# 別ターミナルから、docker run実施。この時に、環境変数DISPLAYを指定。
docker run -e DISPLAY=192.168.99.1:0 <GUIの入ったイメージ> <実行したいコマンド>
上記の注意点としては、-e DISPLAY=xxx に指定するのは docker用のネットワークから見たMac側のIPアドレス です。
ifconfigで取得できますので、この例では、192.168.99.1 になります。
% ifconfig
.....
vboxnet3: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether 0a:00:27:00:00:03
inet 192.168.99.1 netmask 0xffffff00 broadcast 192.168.99.255
さっそく立ち上げてみよう!
では、早速実行を。
先日作った日本語フォント入のイメージがあるので、そこから適当にGUIアプリをチョイス。(今回はxbsh)
% docker run -it -e DISPLAY=192.168.99.1:0 --rm takano/protractor-webdriver-ja:1.0 xbsh
少しすると、Mac側のXQuartzが起動し、xbshのウィンドウが表示されました。
あらまあ!な感じです。
前回書いたヘッドレスでのprotractorのテストも、xvfbの部分を無くして直に protractor ..... とコマンドを打つと、Mac側にChromeが飛ばされてテスト実行になります。
もうちょっと詳しく
以上、やりたいことはこれで完了です。
せっかくなので、もうちょっと何が行われているのか確認してみます。
まず、socatは、通常のサーバ間通信(ポートを利用)を、ソケットに振り替えできるツールです。(詳しくなくてすみません)
こちらを利用して、dockerコンテナからdockerホスト経由でMacのport: 6000に来たリクエストを、MacのX用のソケットに渡します。
(exp. DISPLAY=/private/tmp/com.apple.launchd.GLgekQSd9H/org.macosforge.xquartz:0)
Macからtcpdumpしてみると、上記の画面のように、GUIアプリが立ち上がった時点で、dockerホスト経由でdockerコンテナ上で起動したアプリを描画するための通信が、port 6000で発生しています。
うまく起動してくれないときは?
この方法だと、Macのポート6000に対してのインバウンドの通信が発生します。
もし、dockerコンテナ内からGUIアプリを起動してもMac側で画面が描画されない場合は、ファイアウォールでブロックされてしまった可能性があります。
ウィルス対策ソフトやセキュリティソフトの設定も確認してみて下さいね。
#実際わたしはそれで「あれれー?」な状況になりました。