Dockerを使ってGUIアプリケーションを起動するには、起動にちょっと工夫が必要だったり一筋縄では行かないことが多いです。 osrf/rockerというツールを使うと一筋縄では行かない部分を少しだけ簡単にできるので、その使い方を紹介します。
今回紹介する方法を確認したのはUbuntuのみ(Windows/macOSでは未確認)です。
動作するUbuntuのディストリビューションが異なるROSのディストリビューションを複数対象(Ubuntu 18.04+ROS MelodicとUbuntu 20.04+ROS Noeticなど)としてROSパッケージを開発したい。でもそのときにOSやPCは切り替えたくない。という状況を想定して紹介します。
この記事はROS Advent Calendar 2021の17日目として投稿しています。
概要
Dockerを使ってGUIアプリケーションを起動する(X11を利用する)ためには、起動に-e DISPLAY=$DISPLAYや-v /tmp/.X11-unix:/tmp/.X11-unixなどのオプションを指定したりする必要があります。SpritaroさんのQiitaの記事が詳しいです。

さらにNVIDIAのGPUが搭載されている場合は--gpuオプションを指定したり、NVIDIA_VISIBLE_DEVICES変数を定義したりなどとにかく大変です。
これを「イイ感じ」に楽にしてくれるosrf/rockerというPython製のツールがあります。 README読んだだけでは実際の運用をイメージするのが難しいと思うので、この記事ではその使い方を紹介します。
具体的にはUbuntuがインストールされたPCでROS MelodicとNoetic、ROS 2 FoxyとGalacticの合計4種類のROSディストリビューション向けのパッケージを開発・メンテナンスするという状況でOSやPCを切り替えずに済むような開発環境の構築方法とその使い方を紹介します。
X11(X Window System)とDockerについては以下の記事が参考になると思います。

とりあえず動かしてみたいという方、macOSやWindowsでも試したいという方はWebブラウザ経由でアクセスできる方法ならより簡単に扱えると思います。

動作環境
Ubuntuのみ(Windows/macOSでは未確認)です
今回使用した環境は以下の通りです。
-
CPU: Intel Core i5-9600K
-
GPU: NVIDIA GeForce RTX 2070 SUPER
-
OS: Ubuntu 18.04.5
-
Docker: 20.10.4 (build d3cb89e)
-
NVIDIA Driver: 460.39
-
nvidia-docker2: 2.6.0-1
-
osrf/rocker: v0.2.7
GPUのドライバやDockerのインストールについてはここでは詳細は省略します。
基本的には現時点ではDockerをインストールし、その後nvidia-docker2をインストールするのが良さそうです。
ややこしいのですが、ググって出てくる情報はnvidia-dockerコマンドのためのnvidia-docker2について(2019年以前の古い情報)とNVIDIA
Container Toolkitをインストールするためのnvidia-docker2について(2021年12月17日現在最新の情報)の情報が混じっています。
インストール方法についてはNVIDIA JapanのMediumが参考になると思います。

osrf/rockerについて
osrf/rockerはOpen Roboticsがメンテナンスしているツールです。 Dockerコンテナを起動する際にNVIDIAのGPUのサポートをしたり、ユーザを設定したりしてくれます。
※Dockerコンテナは基本的にrootユーザで起動することが多いので、コンテナ内で編集したファイルは所有者がrootになってしまって一般ユーザからファイルが扱いにくくなったりします。Dockerコンテナ起動時にユーザを適切に設定することで、ファイルのパーミッションや所有者の問題を回避できます。
実はROS Japan UG #42 LT大会の「ROS+Docker環境構築手法n選」でちょっとだけ紹介していました。
ちなみにRの実行環境の「Rocker」も存在するそうです。ややこしい。
本記事では以後、単に「rocker」と書いた場合は「osrf/rocker」を指します。
rockerのインストール方法
rockerはAPTでインストールすることをおすすめします。
APTでROSをインストールできるようにsources.listを更新しておけば(apt installでROSをインストールできるようにしておけば)以下のコマンドでインストールできます。
`sudo apt install python3-rocker`rockerの基本的な使い方
rockerの基本的な使い方は以下のコマンドになると思います。
NVIDIAのGPUありの場合
`rocker --nvidia --x11 --user --home osrf/ros:noetic-desktop-full`NVIDIAのGPUなしの場合
`rocker --x11 --user --home osrf/ros:noetic-desktop-full`このコマンドでUbuntu 18.04がインストールされたPCでもROS Noeticの環境を起動することができるようになります。
noeticをmelodicに置き換えて実行すればROS Melodicの環境を起動することもできます。もちろんUbuntu 20.04がインストールされたPCでも使えます。
Ubuntu18.04でROS Noeticが扱えるだけでもかなりありがたいのですが、このコマンドだけだと私の場合は以下のような不便さを感じることがありました。
-
ROSのワークスペースとしてよく使用する
~/catkin_wsや~/ros2_wsを都度ビルドしないといけないので大変 -
必要なパッケージが入っていないので都度インストールするのが大変
-
インストールされているパッケージが使いたいバージョンと合わないので都度インストールするのが大変
これらの問題を解決するために、ワークスペースについてはディレクトリ構造を見直し、自分で使いたいDockerイメージを作ることにしました。
rockerで扱いやすいワークスペースの構成
ROSのワークスペース(よく使用するのは~/catkin_wsや~/ros2_ws)は基本的にはディストリビューションごとに用意する必要があります。
ROS MelodicでビルドしたものをROS Noeticでそのままsource devel/setup.bashしても基本的にはうまく動かない場合が多いです。
よく使われる~/catkin_wsや~/ros2_wsのままだとROS MelodicとROS Noeticでワークスペースを使いまわすことになり、都度devel/installやbuildなどを削除してビルドし直さないといけないので大変です。
そこで以下のようなディレクトリ構成に変えました。
`ros├── dashing│ ├── build│ ├── install│ ├── log│ └── src├── foxy│ ├── build│ ├── install│ ├── log│ └── src├── galactic│ ├── build│ ├── install│ ├── log│ └── src├── melodic│ ├── build│ ├── devel│ ├── log│ └── src└── noetic ├── build ├── install ├── log └── src`この構成にすればrockerコマンドでDockerコンテナ起動後、以下のようにコマンドを実行すれば、roslaunch/ros2 launchが実行できます。
ROS Melodicの場合
`cd ~/ros/melodic# 必要に応じてcatkin buildsource devel/setup.bash`ROS 2 Foxyの場合
`cd ~/ros/foxy# 必要に応じてcolcon build --symlink-installsource install/setup.bash`Dockerイメージについて
Open Roboticsがメンテンスしているosrf/rosのイメージは必要最小限の構成となっており、Gitやtmuxなどがインストールされていません。
そこで、しばらく使ってみて必要そうだとわかったソフトウェアを大体インストールした構成のDockerfileを公開しました。
Dockerfileの使い方
Dockerfileをダウンロードして編集し、ビルドする方法を紹介します。
今回はROS 2 Foxyのイメージに追加でros-foxy-turtlebot3をインストールしたい場合を例にします。
git cloneコマンドでダウンロードします。
`git clone https://github.com/Tiryoh/docker-ros2.git`foxy/Dockerfileを編集します。
` apt-get install -y --no-install-recommends ros-${ROS_DISTRO}-gazebo-ros-pkgs ros-${ROS_DISTRO}-xacro ros-${ROS_DISTRO}-joint-state-publisher-gui && \+ apt-get install -y --no-install-recommends ros-foxy-turtlebot3 && \ rm -rf /var/lib/apt/lists/*`docker-ros2/foxyディレクトリでdocker buildを実行しDockerイメージを作成します。
`docker build -t tiryoh/ros2:foxy .`先程のrockerコマンドでDockerコンテナを起動します。
`rocker --nvidia --x11 --user --home tiryoh/ros2:foxy`Bashが起動します。

lsコマンドでホストマシンのファイルへアクセスできることも確認できます。

rviz2と入力して実行するとRViz2が起動します。

--nvidiaオプションをつけてrockerを実行した場合はGUIがGPUを利用できていることも確認できます。
rockerで起動したDockerコンテナ内でGazeboを起動し、ホストマシンでnvidia-smiを実行して確認しました。

実際の使い方案
「ROS Melodic/ROS Noetic/ROS 2 Foxy/ROS 2 Galactic向けにROSパッケージを開発したい」というような場面では、本記事内で紹介したrockerで扱いやすいワークスペースの構成に合わせてそれぞれに必要なパッケージを入れておき、rockerでDockerコンテナを起動してROSパッケージの動作確認をするような運用ができると思います。
複数のパッケージをgit cloneしてくるのは大変だと思うのでvcstoolを活用できるとよいと思います。
ROS Melodic用Dockerコンテナ起動
`rocker --nvidia --x11 --user --home tiryoh/ros:melodic`ROS Noetic用Dockerコンテナ起動
`rocker --nvidia --x11 --user --home tiryoh/ros:noetic`ROS 2 Foxy用Dockerコンテナ起動
`rocker --nvidia --x11 --user --home tiryoh/ros2:foxy`ROS 2 Galactic用Dockerコンテナ起動
`rocker --nvidia --x11 --user --home tiryoh/ros2:galactic`roslaunch実行後、rostopic listを実行するような場合には、すでに起動しているDockerコンテナに別の端末から接続するよりも、tmuxなどのターミナルマルチプレクサを活用する方が便利だと思います。


まとめ
rockerを使う環境を作成するまでの流れ、rockerの基本的な使い方を紹介しました。 さらにrockerを便利に扱う方法としてrockerで便利なROSワークスペースのディレクトリ構成例と、rockerから扱うのに便利なDockerイメージの作り方を紹介しました。
Dockerfile参考になったという方はぜひGitHubリポジトリにStarをつけていただけると励みになります!

FAQ
apt updateをした場合のGPG keyのエラー
`building > Reading package lists...building > W: GPG error: http://packages.ros.org/ros2/ubuntu focal InRelease: The following signatures were invalid: EXPKEYSIG F42ED6FBAB17C654 Open Robotics <info@osrfoundation.org>E: The repository 'http://packages.ros.org/ros2/ubuntu focal InRelease' is not signed.`上記のようにエラーが出る場合はDockerイメージが古い可能性があります。
docker pull osrf/ros:noetic-desktop-fullなどで最新版をダウンロードしてみてください。
ネットワークを--network hostで指定した場合のエラー
一部のイメージでは--network hostを指定した場合にRViz等Qtを使うアプリケーションを起動できず、以下のように異常終了してしまう場合があります。
`$ rvizQStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-daisuke'[ INFO] [1639679761.103031358]: rviz version 1.13.21[ INFO] [1639679761.103057954]: compiled against Qt version 5.9.5[ INFO] [1639679761.103064928]: compiled against OGRE version 1.9.0 (Ghadamon)dbus[38]: The last reference on a connection was dropped without closing the connection. This is a bug in an application. See dbus_connection_unref() documentation for details.Most likely, the application was supposed to call dbus_connection_close(), since this is a private connection. D-Bus not built with -rdynamic so unable to print a backtraceAborted (core dumped)`rockerコマンドに以下のように --privilegedオプションをつけるというのがひとまずの問題回避策のようです。
`rocker --nvidia --x11 --user --network host --privileged --volume ~/ros2_ws/src ~/.bashrc -- tiryoh/ros2:foxy`ホストマシンの/var/log/syslogを確認すると以下のようなエラーが出ていました。
`dbus-daemon: apparmor="DENIED" operation="dbus_method_call" bus="accessibility" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="Hello" mask="send" name="org.freedesktop.DBus" pid=17471 label="docker-default" peer_label="unconfined"`これは既知の問題で、DockerのコアであるMobyでもIssueが作成されています。
参考

rockerのオプション
`$ rocker --helpExtension volume doesn't support default arguments. Please extend it.usage: rocker [-h] [--noexecute] [--nocache] [--nocleanup] [--pull] [-v] [--dev-helpers] [--devices [DEVICES [DEVICES ...]]] [--env NAME[=VALUE] [NAME[=VALUE] ...]] [--env-file ENV_FILE] [--git] [--git-config-path GIT_CONFIG_PATH] [--home] [--name NAME] [--network {host,none,bridge}] [--nvidia] [--privileged] [--pulse] [--ssh] [--user] [--user-override-name USER_OVERRIDE_NAME] [--user-preserve-home] [--volume HOST-DIR[:CONTAINER-DIR[:OPTIONS]] [HOST-DIR[:CONTAINER-DIR[:OPTIONS]] ...]] [--x11] [--mode {interactive,non-interactive,dry-run}] [--image-name IMAGE_NAME] [--extension-blacklist [EXTENSION_BLACKLIST [EXTENSION_BLACKLIST ...]]] image [command [command ...]]
A tool for running docker with extra options
positional arguments: image command
optional arguments: -h, --help show this help message and exit --noexecute Deprecated (default: False) --nocache --nocleanup do not remove the docker container when stopped (default: False) --pull -v, --version show program's version number and exit --dev-helpers add development tools emacs and byobu to your environment (default: None) --devices [DEVICES [DEVICES ...]] Mount devices into the container. (default: None) --env NAME[=VALUE] [NAME[=VALUE] ...], -e NAME[=VALUE] [NAME[=VALUE] ...] set environment variables (default: []) --env-file ENV_FILE set environment variable via env-file (default: None) --git Use the global Git settings from the host (/etc/gitconfig and ~/.gitconfig) (default: None) --git-config-path GIT_CONFIG_PATH Override the path to the git config default: /home/daisuke/.gitconfig (default: /home/daisuke/.gitconfig) --home mount the users home directory (default: None) --name NAME Name of the container. (default: ) --network {host,none,bridge} What network configuration to use. (default: None) --nvidia Enable nvidia (default: None) --privileged give extended privileges to the container (default: None) --pulse mount pulse audio devices (default: None) --ssh Forward SSH agent into the container (default: None) --user mount the current user's id and run as that user (default: None) --user-override-name USER_OVERRIDE_NAME override the current user's name (default: None) --user-preserve-home Do not delete home directory if it exists when making a new user. (default: False) --volume HOST-DIR[:CONTAINER-DIR[:OPTIONS]] [HOST-DIR[:CONTAINER-DIR[:OPTIONS]] ...] volume volumes in container (default: None) --x11 Enable x11 (default: None) --mode {interactive,non-interactive,dry-run} Choose mode of operation for rocker (default: interactive) --image-name IMAGE_NAME Tag the final image, useful with dry-run (default: None) --extension-blacklist [EXTENSION_BLACKLIST [EXTENSION_BLACKLIST ...]] Prevent any of these extensions from being loaded. (default: [])`更新履歴
2022年10月13日
rockerの基本的な使い方で指定するDockerイメージのタグ名について追記
2022年10月24日
DockerでGUIを表示するときの仕組みについて、Spritaroさんの記事へのリンクを追加
関連記事
- (Updated )ROS/ROS2のGUIをWebブラウザ経由でお手軽に試せるDockerfileを公開しましたROS/ROS 2のGUIをWebブラウザ経由でお手軽に試せるDockerfileとDockerイメージを公開しています。その特徴と使用方法を紹介します。
- [2020年1月版] ROS2の環境構築方法この記事は2019年4月に書いた「[[2019年4月版] ROS2の環境構築方法](/archives/2150)」の改訂版です。
- (Updated )[2019年4月版] ROS2の環境構築方法[2020年2月18日追記] 2020年1月版を公開しています。
- (Updated )CHAMPをROS 2 Humbleへアップグレードした際にやったこと4脚ロボット制御用のROSパッケージであるCHAMPを、ROS 2 Humbleに対応させるためにPull Requestを作成しました。その際に遭遇した内容については、その他のROS 2パッケージにおいてもROS 2 GalacticからROS 2 Humbleに移行する際に影響する可能性がありそうなので共有します。
- (Updated )メモリ2GB版Jetson NanoでDocker内のROSを使うまでJetson Nano 2GB Developer Kit(メモリ2GB版Jetson Nano)でROSインストール済みのDockerイメージを用意して、コンテナ内のROSを使うまでをメモします。
