Docker・rocker でGUIとGPUが使えるROS 2 Humbleの環境を作る

# はじめに

Nvidia DockerでGUIとGPUが使えるDocker イメージを作成してrockerでコンテナを起動するメモ
同様のDockerファイルはいろいろ公開されているが余計なものが多いのでDockerfileは自分で作成する


# 環境

ホストPCの環境

| Component  | Version      |
|------------|--------------|
| OS         | Ubuntu 22.04.2 LTS |
| GPU  | NVIDIA GeForce RTX 3050Ti |
| NVIDIAドライバ         | 530.30.02|
| Docker  | 23.0.5 |


# Docker ・ Nvidia-dockerのインストール


### Docker 

```bash
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt-get update
sudo apt-get install docker-ce
```

### nvidia-docker2

```bash
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install nvidia-docker2
sudo systemctl restart docker.service
```

https://www.ibm.com/docs/ja/maximo-vi/continuous-delivery?topic=planning-installing-docker-nvidia-docker2


# Dockerfileの作成

適当な場所にDockerfileを作る　
説明はコメントを参照


```txt:Dockerfile
# ベースイメージの設定
FROM nvidia/opengl:base-ubuntu22.04 

# 環境変数の設定
ENV DEBIAN_FRONTEND=noninteractive
ENV __NV_PRIME_RENDER_OFFLOAD=1
ENV __GLX_VENDOR_LIBRARY_NAME=nvidia

# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \
    curl \
    gnupg \
    lsb-release

# ROSのリポジトリをsource listに追加
ENV UBUNTU_CODENAME=focal
RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - \
    && echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list

# ROS2のインストール
RUN apt-get update && apt-get install -y \
    ros-humble-desktop

# colconのインストール
RUN apt-get install -y python3-colcon-common-extensions

# Gazeboのインストール
RUN apt-get install -y gazebo \
    ros-humble-gazebo-*

# rqtのプラグインをインストール
RUN apt-get install -y ros-humble-rqt-*

# ワークスペースの作成
RUN mkdir -p ~/ros2_ws/src
WORKDIR /root/ros2_ws/
RUN /bin/bash -c '. /opt/ros/humble/setup.bash; colcon build'

# エントリーポイントを設定
COPY ./ros_entrypoint.sh /
RUN chmod +x /ros_entrypoint.sh
ENTRYPOINT ["/ros_entrypoint.sh"]

# コマンドを設定
CMD ["bash"]
```

Dockerコンテナで起動したrviz2やGazeboがGPUを使って描画できるようにOpenGLが入ったubuntu22.04のイメージをベースにする。

```txt:Dockerfile
FROM nvidia/opengl:base-ubuntu22.04 
```

Dockerfileと同じディレクトリに`ros_entrypoint.sh`を作成する。
毎回コンテナ起動する度にsource ../setup.bashを実行するのは面倒なのでここに記述して`COPY ./ros_entrypoint.sh /
` でコンテナ内にコピーする

```bash
vim ros_entrypoint.sh
sudo chmod +x ros_entrypoint.sh
```

```sh:ros_entrypoint.sh
#!/bin/bash
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
exec "$@"
```

# Dockerfileのビルド

Dockerfileがあるディレクトリで以下を実行
`ros2_humble`には適当な名前を設定

```bash
 docker build -t ros2_humble .
```

imageができているか確認

```bash
docker images
REPOSITORY                               TAG                               IMAGE ID       CREATED         SIZE
ros2_humble                              latest                            c124ead937a3   9 hours ago     4.23GB
```

# rocker でDockerコンテナの起動


## rockerのインストール

```bash
sudo apt update && sudo apt install curl gnupg lsb-release
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
sudo apt update
sudo apt-get install python3-rocker
```


https://github.com/autowarefoundation/autoware/tree/main/ansible/roles/rocker#manual-installation

## コンテナの起動

以下先程作成したros_humbleイメージのコンテナを起動するコマンドの例

```bash
rocker --nvidia --x11 --user --network host --privileged --nocleanup --name humble ros2_humble:latest 
```

--nvidia  : GPUを有効にする
--x11 : X11を有効にしてGUIを使えるようにする
--network host : ホストPCとネットワークを共有して他PCとROS2通信したり、Ethernetのデバイスを使ったりする
--privileged : USBデバイスなどを使えるように
--nocleanup : コンテナstop時にコンテナが削除されないようにする
--name humble　: コンテナに名前をつける

2回目以降起動するとき

```bash
docker start humble
docker attach humble
```

## rviz2, Gazeboの動作確認

docker コンテナ内でrviz2 やGazeboを起動
ホストPCまたはDockerコンテナ内のターミナルで`nvidia-smi` を実行してrviz2またはGazeboのプロセス名前があればOK

```bash
rviz2
nvidia-smi
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399606/5be321c8-8807-f31a-1862-55efe69cb884.png)


## 

# rockerのオプション

| オプション | 日本語の説明 |
| --- | --- |
| -h, --help | このヘルプメッセージを表示して終了します |
| --noexecute | 廃止予定（デフォルト：False） |
| --nocache | キャッシュを無効にします |
| --nocleanup | コンテナが停止したときにDockerコンテナを削除しない（デフォルト：False） |
| --pull | Dockerイメージをプルします |
| -v, --version | プログラムのバージョン番号を表示して終了します |
| --dev-helpers | 開発ツールのemacsとbyobuを環境に追加します（デフォルト：None） |
| --devices [DEVICES [DEVICES ...]] | デバイスをコンテナにマウントします（デフォルト：None） |
| --env NAME[=VALUE] [NAME[=VALUE] ...], -e NAME[=VALUE] [NAME[=VALUE] ...] | 環境変数を設定します（デフォルト：[]） |
| --env-file ENV_FILE | env-fileを介して環境変数を設定します（デフォルト：None） |
| --git | ホストからのグローバルGit設定を使用します（/etc/gitconfigおよび~/.gitconfig）（デフォルト：None） |
| --git-config-path GIT_CONFIG_PATH | git設定へのパスを上書きします（デフォルト：/home/daisuke/.gitconfig） |
| --home | ユーザーのホームディレクトリをマウントします（デフォルト：None） |
| --name NAME | コンテナの名前（デフォルト：） |
| --network {host,none,bridge} | 使用するネットワーク設定（デフォルト：None） |
| --nvidia | nvidiaを有効にします（デフォルト：None） |
| --privileged | コンテナに拡張権限を付与します（デフォルト：None） |
| --pulse | pulseオーディオデバイスをマウントします（デフォルト：None） |
| --ssh | SSHエージェントをコンテナに転送します（デフォルト：None） |
| --user | 現在のユーザーIDをマウントし、そのユーザーとして実行します（デフォルト：None） |
| --user-override-name USER_OVERRIDE_NAME | 現在のユーザー名を上書きします（デフォルト：None） |
| --user-preserve-home | 新しいユーザーを作成するときにホームディレクトリが存在する場合は削除しません|
| --volume HOST-DIR[:CONTAINER-DIR[:OPTIONS]] [HOST-DIR[:CONTAINER-DIR[:OPTIONS]] ...] | コンテナ内のボリュームをマウントします（デフォルト：None） |
| --x11 | x11を有効にします（デフォルト：None） |
| --mode {interactive,non-interactive,dry-run} | rockerの操作モードを選択します（デフォルト：interactive） |
| --image-name IMAGE_NAME | 最終イメージにタグをつけます。dry-runと一緒に有用です（デフォルト：None） |
| --extension-blacklist [EXTENSION_BLACKLIST [EXTENSION_BLACKLIST ...]] | これらの拡張機能のロードを防ぎます（デフォルト：[]） |



# 参考


https://github.com/Tiryoh/docker-ros2/tree/master

https://memoteki.net/archives/4471#index_id14

https://lilaboc.work/archives/29831169.html

https://qiita.com/hiro-han/items/e9b69e763adc44757a6c

https://qiita.com/porizou1/items/5dd915402e2990e4d95f