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でも使えます。
【2022年10月13日追記】
ROS 2用イメージの場合はタグの命名規則が異なるようです。
Foxyの場合はDockerイメージ名がosrf/ros:foxy-desktop
となります。その他に使用できるタグ名についてはDocker Hubから確認できます。
https://hub.docker.com/r/osrf/ros/tags
https://hub.docker.com/_/ros/tags
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 build
source devel/setup.bash
ROS 2 Foxyの場合
cd ~/ros/foxy
# 必要に応じてcolcon build --symlink-install
source 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 <[email protected]>
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を使うアプリケーションを起動できず、以下のように異常終了してしまう場合があります。
$ rviz
QStandardPaths: 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 backtrace
Aborted (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 --help
Extension 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さんの記事へのリンクを追加
コメント