12
8

ROS 2のDockerコンテナ間でpub/subするとき、docker runでどのオプションを付ければいいの?

Last updated at Posted at 2024-07-21

1. はじめに

ROS 2のDockerコンテナ間通信をする方法を検索すると「docker runオプションに--net=host --ipc=hostを付けよう」という言及がWeb上の記事で散見されます。一方、このオプションを付ける理由まで書かれているものが非常に少ないです。理由がよくわからないと非常に気持ち悪いのでもう少し掘り下げて整理していきます。

2. シチュエーション別おすすめdocker runオプション

ユースケースにもよると思うので、本記事ではDDSそのものの比較には言及しないこととします。気になる方はhttps://discourse.ros.org/t/ros-2-alternative-middleware-report/33771を読んでみてください。

本記事では基本的にROS 2 HumbleのデフォルトであるFast DDSを使うとして、シチュエーション別docker runオプションを記載します。

ここでは例として--shm-size=512mbとして、共有メモリサイズを512MBとしていますが、ご自身のユースケースに応じて適宜調整してください。

3. 動作確認条件

以下に動作確認で用いた環境、動作確認内容について列挙します。

3.1 動作確認に用いた環境

  • ホストOS:Ubuntu 22.04(x86_64)
  • Docker CLI
    • docker-ce 24.0.6
  • ROS 2公式Dockerイメージ ros:humble-ros-core を用いた
  • ROS 2ディストリビューション:Humble
  • DDS
    • Fast DDS
      • ros-humble-fastrtps 2.6.8
      • ros-humble-rmw-fastrtps-cpp 6.2.6
      • ros-humble-rmw-fastrtps-shared-cpp 6.2.6
    • Cyclone DDS
      • ros-humble-cyclonedds 0.10.4
      • ros-humble-rmw-cyclonedds-cpp 1.3.4

3.2 動作確認内容

  • 同一マシン上で2つのDockerコンテナを起動し、片方のコンテナでpub、もう片方のコンテナでsubを行った
  • pubコマンドは以下の通り
ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
  • subコマンドは以下の通り
ros2 topic echo /turtle1/cmd_vel

3.3 docker runオプション

今回、以下のパターンで検証していきます。

  • --net=bridge
  • --net=host
  • --net=host --ipc=host

詳細なオプションは以降に記載します。

3.3.1 net=bridge

--netオプションのデフォルト値である、--net=bridgeを指定します。

docker run --rm -it \
           ros:humble-ros-core \
           bash

3.3.2 net=host

--net=hostを指定します。

docker run --rm -it \
           --net=host \
           ros:humble-ros-core \
           bash

3.3.3 net=host ipc=host

--net=host--ipc=hostを指定します。

docker run --rm -it \
           --net=host \
           --ipc=host \
           ros:humble-ros-core \
           bash

4. 動作確認結果

同一マシン上の2つのコンテナ間でROS 2のpub/subができるかどうかの確認結果を下表に示します。ここでは比較対象としてCyclone DDSの場合の結果も併せて記載しています。

DDS\docker runオプション net=bridge net=host net=host
ipc=host
Fast DDS OK NG OK
Cyclone DDS OK OK OK
  • OK:同一マシン上の2つのコンテナ間でROS 2のpub/subができる
  • NG:同一マシン上の2つのコンテナ間でROS 2のpub/subができない
    • ただし、ros2 topic listでトピック一覧には表示される

この結果からFast DDSかつnet=hostオプションのみの場合を除いて、同一PC上でROS 2のDockerコンテナを複数起動して、コンテナ間でROS 2のpub/subができていることがわかります。

さて、docker runオプションやDDSの違いでなぜこのような挙動の差異が生じるのでしょうか?もう少し掘り下げて見ていきましょう。

5. 前提知識

ここでは詳細な確認をする前に必要な前提知識をおさらいしていきます。

5.1 docker runオプション

5.1.1 netオプション

docker runのnetオプションでネットワークドライバを指定できます(https://docs.docker.com/network/drivers/参照)。https://zenn.dev/suiudou/articles/14249a918ec93b#hostネットワークの図がわかりやすいでしょう。

5.1.2 ipcオプション

docker runのipcオプションでDockerコンテナにおけるプロセス間通信(Inter-Process Communication)の名前空間を変更することができます。https://docs.docker.com/reference/cli/docker/container/run/#ipcに以下の説明があります。

Value Description
"" Use daemon's default.
"none" Own private IPC namespace, with /dev/shm not mounted.
"private" Own private IPC namespace.
"shareable" Own private IPC namespace, with a possibility to share it with other containers.
"container:" Join another ("shareable") container's IPC namespace.
"host" Use the host system's IPC namespace.

--ipc=hostの場合、プロセス間通信においてホストと同一の名前空間が用いられることになります。また、ipcオプションを明示的に指定しない場合についてはhttps://docs.docker.com/reference/cli/docker/container/run/#ipcに以下の記載があります。

If not specified, daemon default is used, which can either be "private" or "shareable", depending on the daemon version and configuration.

デーモンのバージョン、コンフィグレーションにもよりますが、デフォルト値となるprivateshareableのいずれかが使用されるとあります。そこでhttps://docs.docker.jp/engine/reference/commandline/dockerd.htmlを読むと

--default-ipc-mode string
Default mode for containers ipc ("shareable" | "private") (default "private")

とあり、デフォルトのIPCモードはprivateとあります。そのため、IPCの名前空間はコンテナ毎に独立していることになります。

5.2 Fast DDS

ここではFast DDSのTransportについて簡単におさらいしていきます。Fast DDSでは以下のTransportが実装されています。
https://fast-dds.docs.eprosima.com/en/latest/fastdds/transport/transport.html

  • UDPv4 Transport
  • UDPv6 Transport
  • TCPv4 Transport
  • TCPv6 Transport
  • Shared Memory Transport

Fast DDSのTransport実装を図示したものを以下に示します(https://fast-dds.docs.eprosima.com/en/latest/_images/transport_comparison.svgから引用)。

本記事ではFast DDSにてデフォルトで有効になっている以下のTransportに着目します。

  • UDPv4 Transport
  • Shared Memory Transport

5.2.1 UDPv4 Transport

5.2.2 Shared Memory Transport

また、同時に複数のtransportが有効になっている場合の挙動についてはhttps://fast-dds.docs.eprosima.com/en/latest/fastdds/transport/shared_memory/shared_memory.htmlに記載があります。

In case that several transports are enabled, the discovery traffic is always performed using the UDP/TCP transport, even if the SHM transport is enabled in both participants running in the same machine. This may cause discovery issues if one or several of the participants only has SHM enabled and other participants use some other transport at the same time. Also, when two participants on the same machine have SHM transport enabled, the user data communication between them is automatically performed by SHM transport only. The rest of the enabled transports are not used between those two participants.

6. 調査

ここでは「4. 動作確認結果」で得られた結果とDocker、DDSの処理の対応関係についてもう少し掘り下げて見ていきます。

6.1 同一PC上で-net=hostのみだとコンテナ間でpub/subできないのはなぜ?(Fast DDS)

https://fast-dds.docs.eprosima.com/en/latest/fastdds/transport/shared_memory/shared_memory.html

–ipc=host: This option shares the host’s shared memory mechanism with the containers. Without it, Fast DDS will identify both containers as the same host, but since they will have separate shared memory spaces, they will not be able to communicate with one another.

という説明があります。--ipcオプションを明示的に指定しない場合、コンテナ間で共有メモリの名前空間が別になります。そのため、コンテナ間でShared Memory Transportを使って通信できない状態になっており、コンテナ間でROS 2のpub/subできなくなっています。

6.2 同一PC上で-net=hostのみだと別コンテナのトピックは見えるのはなぜ?(Fast DDS)

「4. 動作確認結果」で

  • NG:同一マシン上の2つのコンテナ間でROS 2のpub/subができない
    • ただし、ros2 topic listでトピック一覧には表示される

とありました。「ros2 topic listでトピック一覧には表示される」のはなぜでしょうか?これは「5.2.2 Shared Memory Transport」で説明した以下の処理に起因しています。

In case that several transports are enabled, the discovery traffic is always performed using the UDP/TCP transport, even if the SHM transport is enabled in both participants running in the same machine.

Fast DDSではUDPv4 Transport、Shared Memory Transportがデフォルトで有効になっています。また、このケースではdiscovery trafficはUDPv4 Transportで行われているため、コンテナ間で共有メモリの名前空間が同じかどうかは関係ありません。そのため、ros2 topic listでトピック一覧には表示されることになります。

6.3 同一PC上で--net=hostのみでもコンテナ間でpub/subできるのはなぜ?(Cyclone DDS)

https://github.com/ros2/rmw_cyclonedds/blob/rolling/shared_memory_support.mdに以下の説明があります。

This rmw_cyclonedds implementation uses cyclonedds which includes support for fast Shared Memory data transfer based on iceoryx. Shared Memory is disabled by default but can be enabled easily by providing a cyclonedds.xml configuration file.

Cyclone DDSでは共有メモリを使ったデータ転送はデフォルトで無効化されているため、--ipc=hostを付けなくてもコンテナ間でROS 2のpub/subができています。

6.4 同一PC上で--ipc=hostなしでもShared Memory Transportを使ってコンテナ間でpub/subできるか?(Fast DDS)

オプションは以下の通りです。前述した通り、コンテナ間で共有メモリの名前空間が別になっていたため、Fast DDSではコンテナ間でROS 2のpub/subができていませんでした。

docker run --rm -it \
           --net=host \
           ros:humble-ros-core \
           bash

そのため、docker runオプションに--volume=/dev/shm:/dev/shm:rw、共有メモリのデバイスファイルをマウントすることでコンテナ間でROS 2のpub/subができるようになります。

docker run --rm -it \
           --volume=/dev/shm:/dev/shm:rw \
           --net=host \
           ros:humble-ros-core \
           bash

6.5 net=bridgeのみだとpub/subできていたのはなぜ?(Fast DDS)

《こちらは調査中です》

「4. 動作確認結果」で--net=bridgeのとき、IPC関連のオプションなしでもpub/subできていました。この挙動の理由について調べてみます。

6.5.1 IPC名前空間を調べる

--net=bridgeでコンテナを2つ起動してIPC名前空間を調べてみます。コンテナ(1)の結果は以下の通りです。

$ ls -l /proc/self/ns/ipc
lrwxrwxrwx 1 humble humble 0 Jul 21 04:37 /proc/self/ns/ipc -> 'ipc:[4026533262]'

コンテナ(2)の結果は以下の通りです。

$ ls -l /proc/self/ns/ipc
lrwxrwxrwx 1 humble humble 0 Jul 21 04:37 /proc/self/ns/ipc -> 'ipc:[4026533374]'

2つのコンテナでIPC名前空間は同一にはなっていないようです。

6.5.2 /dev/shmをマウントしない

docker runオプションで--ipc=noneとして/dev/shmをマウントしないようにしてコンテナ間でpub/subを確認してみます。

$ ros2 topic echo /turtle1/cmd_vel
2024-07-21 04:32:47.964 [RTPS_TRANSPORT_SHM Error] Failed to create segment 15f520708af5b59c: No such file or directory -> Function compute_per_allocation_extra_size
2024-07-21 04:32:47.964 [RTPS_TRANSPORT_SHM Error] Failed to create Shared Memory Manager for domain fastrtps: No such file or directory -> Function create
2024-07-21 04:32:47.964 [RTPS_PARTICIPANT Error] Unable to Register SHM Transport. SHM Transport is not supported in the current platform. -> Function RTPSParticipantImpl
linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 1.8

Shared Memory Transportの初期化で失敗していますが、UDPv4 Transportでpub/subできているようです。

6.5.3 FASTDDS_BUILTIN_TRANSPORTSを変更する

https://fast-dds.docs.eprosima.com/en/latest/fastdds/env_vars/env_vars.html#fastdds-builtin-transportsを参考にして環境変数FASTDDS_BUILTIN_TRANSPORTSを変更してコンテナ間のpub/sub成否を確認します。結果は以下の通りです。

FASTDDS_BUILTIN_TRANSPORTS コンテナ間のpub/sub成否
DEFAULT OK
UDPv4 OK
SHM NG

この結果からUDPv4 Transportでpub/subできているようです。

6.6 同一PC上で--ipc=hostなしでもコンテナ間でpub/subできるか?(Fast DDS)

同一PC上のコンテナ間でFast DDS、Shared Memory Transportを使うために--ipc=hostが必要です。逆に言うとShared Memory Transportを使わないようにし、UDP Transportのみを使うようにすれば--ipc=hostを付けなくてもよくなります。

https://fast-dds.docs.eprosima.com/en/latest/fastdds/env_vars/env_vars.html#fastdds-builtin-transportsを参考に以下のコマンドを実行してUDPv4 Transportを使うようにします。
https://tech.aptpod.co.jp/entry/2023/09/25/170000にあるようにUDP Transportを使うようなコンフィグレーションファイル (fastrtps-profile.xml)を用いる方法もあります。

export FASTDDS_BUILTIN_TRANSPORTS=UDPv4

このようにすることで--ipc=hostなしでもコンテナ間でROS 2のpub/subができるようになります。

6.7 --net=hostオプションは要らない?

ここまでの説明で--ipc=hostだけ付けていればよくて--net=hostは要らないのでは?と思われる方が居るかもしれません。ROS 2でpub/subするコンテナが同一マシン内だけであれば--net=hostは要らない(=デフォルトの--net=bridgeを使う)ので問題ありませんが、ROS 2でpub/subするコンテナが同一ネットワーク上の異なるPC間にある場合、--net=bridgeではpub/subできません。このような使い方をする場合は--net=hostが必要になります。

6.8 Dockerコンテナで共有メモリの割り当てはどうなっているの?

Dockerドキュメントのhttps://docs.docker.jp/engine/reference/commandline/dockerd.html

--default-shm-size bytes
Default shm size for containers (default 64MiB)

とあり、デフォルトは共有メモリのサイズは64MiBとなっています。そのため、このサイズだと不十分なユースケースであればdocker run--shm-sizeオプションで共有メモリの割り当てを増やすと良いでしょう。
https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources

--shm-sizeオプションで共有メモリを1GB割り当てるオプションを以下に示します。

--shm-size=1gb

参考URL

12
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8