ROS2 × Docker で Fast DDS を UDPv4 のみにする理由
「ROS2 × Docker」で「Fast DDS」を「UDPv4 のみ」にする理由をまとめました。
1. はじめに
「ROS2」を「Docker」内で動かしていると、「ノードが見えない」「Topic が届かない」といった通信トラブルに遭遇することがあります。その対策としてよく紹介されるのが Fast DDS を UDPv4 のみにする設定です。
この記事では、その理由を DDS の通信トランスポートの仕組みから整理します。
2. DDS の通信トランスポート
「Fast DDS」(ROS2 の RMW 実装の一つ)は、通信手段を「Transport」という単位で扱います。
代表的なものは次の 3 種類です。

3. Fast DDS のデフォルト動作
Fast DDS は通常、次のように通信方法を自動選択します。

つまりデフォルトでは「SHM + UDP」が有効になっています。
これはパフォーマンス面では理想的で、
・同一マシン → SHM(高速)
・別マシン → UDP(ネットワーク通信)
という最適な経路が自動的に選ばれます。
4. Docker で問題が起きる理由
4-1. 実際に起きていること
Dockerでは、この自動選択の仕組みがうまく機能しない場合があります。ポイントは 「SHM」(Shared Memory)の扱いです。
Dockerの標準設定では「/dev/shm」が コンテナごとに分離されています。つまり、「Container A」と「Container B」が同じホスト上に存在していても 共有メモリを直接共有できません。
「Fast DDS」は、同一ホスト内のノードを検出すると、「共有メモリが使えるはず」と判断して SHM 通信を優先しようとします。
しかし Dockerコンテナ間で「/dev/shm」が共有されていない場合、
・共有メモリセグメントの作成
・共有メモリのオープン
などが正常に行えず、メッセージの受け渡しに失敗することがあります。
結果として次のような現象が発生します。
・node が見えない
・topic が表示されない
・message が届かない
4-2. SHM が使えない環境との不一致
ここで重要なのは、問題の本質が、「SHMが使えない環境なのに、Fast DDSがSHMを使おうとする不一致」にあるという点です。
補足として、「Fast DDS」は SHM が利用できないと判断した場合に UDP へフォールバック(切り替え)する仕組みを持っています。
しかし Docker のネットワーク構成によっては
・SHM が使えると誤認する
・判定に時間がかかる
・中途半端に接続される
といった状況が起き、通信がブラックホール化する場合があります。
そのため 最初から UDP のみを使うように固定することで、通信の安定性を高めることができます。
4-3. もう一つの理由 - マルチキャスト問題
Dockerでは「UDP マルチキャスト」の扱いも問題になることがあります。
「ROS2」のノード発見(Discovery)は UDP マルチキャストを利用しています。
しかし Dockerでは
・bridge ネットワーク
・docker0 インターフェース
・カスタムネットワーク
などが存在するため、
意図しないインターフェースでマルチキャストが流れることがあります。
これにより
・discovery が不安定になる
・別コンテナの通信が混線する
といった問題が発生する場合があります。
「UDPv4」を明示的に指定することで、通信経路をシンプルにし、不要なインターフェースを避ける効果も期待できます。
5. 対策
5-1. UDP のみにする
この問題を避けるために、「SHM」を無効化して「UDP」のみを使用する設定にします。
「Fast DDS」の XML 設定例です。
<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
<transport_descriptors>
<transport_descriptor>
<transport_id>UdpTransport</transport_id>
<type>UDPv4</type>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="udp_transport_profile" is_default_profile="true">
<rtps>
<userTransports>
<transport_id>UdpTransport</transport_id>
</userTransports>
<useBuiltinTransports>false</useBuiltinTransports>
</rtps>
</participant>
</profiles>この設定のポイントは次の 2 つです。
・builtin transport を無効化
これにより「Fast DDS」のデフォルトのTransport(SHM など)が無効化されます。
<useBuiltinTransports>false</useBuiltinTransports>・UDPv4 を明示的に指定
userTransports に登録することで「UDPv4のみ」を利用する構成になります。
<type>UDPv4</type>この XML を「ROS2」で利用するには、「Fast DDS」に設定ファイルの場所を教える必要があります。
環境変数を設定します。
export FASTRTPS_DEFAULT_PROFILES_FILE=/path/to/fastdds.xmlこれにより、「ROS2」起動時に「Fast DDS」がこの設定を読み込みます。
※ ROS2 のディストリビューションや Fast DDS のバージョンによっては、
他の環境変数設定の影響を受ける場合があるため注意が必要です。
5-2. 別の解決方法(参考)
「UDP」のみにする以外にも、Docker 側の設定で SHM を共有する方法もあります。
例えば次のオプションです。
--ipc=hostこれを付けるとコンテナが ホストの SHMを利用するようになります。
また
--shm-sizeで共有メモリサイズを拡張する方法もあります。
ただしこの方法は
・セキュリティ分離が弱くなる
・コンテナ設計に依存する
ため、実運用ではUDPのみに固定する方法がシンプルで採用されることが多いです。
6. まとめ
Docker環境では
・Fast DDS が SHM を使おうとする
・Docker は SHM をコンテナごとに分離する
という 環境とミドルウェアの不一致が起きます。その結果、ROS2 の通信が失敗することがあります。
そのためトラブル回避として、Fast DDS を UDPv4 のみに固定する設定がよく利用されます。
【おまけ】 ROS2 × Docker を安定させるコツ
「ROS2」を「Docker」環境で安定させるために、次の組み合わせがよく使われます。
・Fast DDS の UDPのみ
・--network=host
・通信 NIC の固定
--network=host は、Docker コンテナがホストのネットワークをそのまま使う設定で、ROS2 の DDS discovery(UDP multicast)が Docker の bridge/NAT に邪魔されないようにするために使われます。
通信 NIC の固定とは、ROS2 / DDS が通信に使うネットワークインターフェース(例:eth0 や wlan0)を1つに指定することです。これにより、Wi-Fi・有線LAN・VPN・docker0 など複数のNICがある環境で 誤ったインターフェースに discovery や通信が流れるのを防げます。
これらを組み合わせることで、ROS2の通信トラブルを大幅に減らすことができます。
