困ったこと
dockerコンテナでOpen AI Gymのサンプルコードを実行しようとしたら、次のようなエラーメッセージが出てしまいました。
Traceback (most recent call last):
File "hello_gym.py", line 8, in <module>
env.render()
File "/usr/local/lib/python3.6/dist-packages/gym/core.py", line 240, in render
return self.env.render(mode, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/gym/envs/classic_control/cartpole.py", line 174, in render
from gym.envs.classic_control import rendering
File "/usr/local/lib/python3.6/dist-packages/gym/envs/classic_control/rendering.py", line 25, in <module>
from pyglet.gl import *
File "/usr/local/lib/python3.6/dist-packages/pyglet/gl/__init__.py", line 244, in <module>
import pyglet.window
File "/usr/local/lib/python3.6/dist-packages/pyglet/window/__init__.py", line 1880, in <module>
gl._create_shadow_window()
File "/usr/local/lib/python3.6/dist-packages/pyglet/gl/__init__.py", line 220, in _create_shadow_window
_shadow_window = Window(width=1, height=1, visible=False)
File "/usr/local/lib/python3.6/dist-packages/pyglet/window/xlib/__init__.py", line 165, in __init__
super(XlibWindow, self).__init__(*args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/pyglet/window/__init__.py", line 570, in __init__
display = pyglet.canvas.get_display()
File "/usr/local/lib/python3.6/dist-packages/pyglet/canvas/__init__.py", line 94, in get_display
return Display()
File "/usr/local/lib/python3.6/dist-packages/pyglet/canvas/xlib.py", line 123, in __init__
raise NoSuchDisplayException('Cannot connect to "%s"' % name)
pyglet.canvas.xlib.NoSuchDisplayException: Cannot connect to "None"
実行環境
実行環境は次のとおりです。
バージョン | |
---|---|
OS | Ubuntu18.04 |
python | 3.6 |
gym | 0.18.0 |
pyglet | 1.5.0 |
xvfb | 2:1.19.6 |
x11vnc | 0.9.13 |
Ubintu18.04ベースのdockerコンテナにvncを設定して、render()の出力結果をブラウザで確認しようとしています。
考えたこと
- VNCの設定ができていない
- X displayの設定ができていない
- gymサンプルコードのエラー(render周り)
- pygletのバージョンが合っていない(pygletは最新を入れていました)
gymのサンプルコードは次のとおりです。
import gym
env = gym.make('CartPole-v0')
env.reset()
for _ in range(1000):
env.render()
env.step(env.action_space.sample()) # take a random action
env.close()
(実はこのコードは、別の理由でエラーが起こるのですが、それはまた別の記事で…)
原因
DISPLAYの設定ができていませんでした。
ターミナルで環境変数を確認します。
$ printenv
一覧がずらずらっと表示されて
略
LANG=C.UTF-8
OLDPWD=/home/user
VISIBLE=now
USER=user
PWD=/home/user/workspace
HOME=/home/user
略
DISPLAY=
の表示がありません。設定したはずなのに…。
DISPLAY 環境変数の設定 (うまくいかなかった例)
次の3つの方法は試しましたが、うまくいきませんでした。
解決策を早く知りたい方はジャンプ
設定法1
もともとはDockerfileの中で設定していました(できているつもりでした)
ENV DISPLAY=:0
でも、コンテナ内の環境変数は設定できていませんでした。
設定法2 docker run
のオプションで設定する
次に試したのがこの方法。
docker run -e DISPLAY=$DISPLAY 以下略
ちなみに、-e
を--env
に変えても、だめでした笑
設定法3 startup.sh
で設定する
startup.sh
は、ざっくり言うとコンテナを起動する際に、実行させることのできるシェルスクリプトです。
(よくわかっていないだけw)
Dockerfileの最後にCMD
命令を記述できますが、複数のコマンドを実行させたい場合に、
それらをstartup.sh
の中に記述することで実行させます。
CMD ["/startup.sh"]
なぜstartup.sh
を使ったかというと、ssh
とvnc
をsupervisord
によって起動させたかったので、/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
は少なくともbashで実行する必要があったからです。
そのため、コマンドを2行記述しました。
#!/bin/bash
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
export DISPLAY=:0
結局この方法でも、エラーは解決しませんでした。
解決策
Dockerfileの中で次のように記述します。
RUN echo "export DISPLAY=:0" >> /etc/profile
これで、コンテナ内の環境変数にDISPLAYを設定することができました。
まとめ
dockerコンテナ内でgym
を実行した際にpyglet.canvas.xlib.NoSuchDisplayException: Cannot connect to "None"
というエラーが表示されたら、
DISPLAYの環境変数が設定できていないかもしれません。
Dockerfile内でRUN echo "export DISPLAY=:0" >> /etc/profile
と実行すると設定できました。