DockerでGUIとGPUが使えるROS2(humble)環境構築

Docker上でGUIとGPUが使えるROS2環境を構築したので、忘備録をかねてDockerfile/Docker Composeファイルを共有します。

# ホストPC環境
- Ubuntu 22.04
- NVIDIA GeForce 1060
- Nvidia Driver 470.141.03
- Cuda 11.4
- Docker 20.10.21
- Docker Compose v2.6.0

上記の通り、ホストPCにはNvidia Driver, Cuda, Docker, Docker Composeを事前にインストールしておきます。

## Dockerfile, Docker Compose
## ファイル構成
```
(root)
├ .env
├ docker-compose.yaml
└ Dockerfile
```

## Dockerfile
Ubuntu 22.04のdocker imageをベースにして、ROS2とNVIDIA Container Toolkitをインストールします。
`/app`ディレクトリに対してホストPCのディレクトリをマウントし、ここにROS2のワークスペースを作成する想定です。
またdocker上でファイル作成をしたとき、ファイルの権限がrootではなく、ホストPCのユーザと同じになるようにしています。

NVIDIA Container Toolkitは、以前のNvidia Dockerの代わりとなるものです。
Dockerのバージョンが18.09以上のとき、dockerコマンドに`--gpu`オプションをつけることでnvidia-dockerではなくdockerでgpuが使用可能となります。
このとき必要となるのがNVIDIA COntainer Toolkitです。詳しくは[コチラの方](https://qiita.com/tkusumi/items/f275f0737fb5b261a868)がまとめて下さっています。

```Dockerfile
FROM ubuntu:22.04

# Timezone, Launguage設定
RUN apt update \
  && apt install -y --no-install-recommends \
     locales \
     software-properties-common tzdata \
  && locale-gen en_US en_US.UTF-8 \
  && update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 \
  && add-apt-repository universe

ENV LANG en_US.UTF-8
ENV TZ=Asia/Tokyo

# Install ROS2
RUN apt update \
  && apt install -y --no-install-recommends \
     curl gnupg2 lsb-release python3-pip vim wget build-essential ca-certificates

RUN 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 $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null

RUN apt update \
  && apt upgrade \
  && DEBIAN_FRONTEND=noninteractive \
  && apt install -y --no-install-recommends \
     ros-humble-desktop \
  && rm -rf /var/lib/apt/lists/*

RUN bash /opt/ros/humble/setup.sh 

# Install Nvidia Container Toollit
RUN distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
  && curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | apt-key add - \
  && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

RUN apt-get update \
  && apt-get install -y --no-install-recommends nvidia-container-toolkit

# Add user and group
ARG UID
ARG GID
ARG USER_NAME
ARG GROUP_NAME

RUN groupadd -g ${GID} ${GROUP_NAME}
RUN useradd -u ${UID} -g ${GID} -s /bin/bash -m ${USER_NAME}

USER ${USER_NAME}

WORKDIR /app

CMD ["/bin/bash"]
```

## Docker Compose
上のDockerfileを使用するにあたって、いつくかパラメータを指定する必要があります。
そのため毎回docker runコマンドを実行するのは面倒なのでDocker Composeファイルを用意しました。

概要は以下になります。
- GUIを使用するための`DISPLAY`や`/tmp/.X11-unix`、`root/.Xauthority`の設定
- GPUを使用するための`deploy`以下の設定。これは[公式](https://docs.docker.jp/compose/gpu-support.html)の設定そのままです
- ホストユーザの設定のためのUID, GIDなど
- rosのワークスペース用ディレクトリのマウント（WORK_SPACE_DIR）

```docker-compose.yaml
version: "3"
services:
  ros2:
    container_name: ros2
    image: ros2
    build:
      context: .
      args:
        - USER_NAME=${USER_NAME}
        - GROUP_NAME=${GROUP_NAME}
        - UID=${UID}
        - GID=${GID}
    environment:
      - DISPLAY=${DISPLAY}
    volumes:
       - /tmp/.X11-unix:/tmp/.X11-unix
       - $HOME/.Xauthority/:/root/.Xauthority
       - ${WORKSPACE_DIR}:/app
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    tty: true
    user: "${UID}:${GID}"
```
## .env
docker-compose.yaml内で使用するパラメータの一覧です。ご使用の環境に合わせて`{ }`を変更して下さい。
このファイルを用意するのが面倒であれば、`docker-compose.yaml`の該当箇所に直接記入してもかまいません。

```.env
USER_NAME={ローカルユーザ名}
GROUP_NAME={ローカルユーザのグループ名}
UID={ローカルユーザのUID}
GID={ローカルユーザのGID}
WORKSPACE_DIR={ROS2用ワークスペースのディレクトリの絶対パス}
```

# 実行
- Build
```
$ docker-compose build
```

- Run
```
$ docker-compose up -d
```

- コンテナ内に入る
```
$ docker-compose exec ros2 /bin/bash
```

- GPUを認識しているか確認（コンテナ内で実行すること）
実行は各環境で変わりますが、コマンドの実行に成功すればdockerコンテナからGPUが使えていることになります
```
$ nvidia-smi
Wed Nov  9 09:02:54 2022       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.141.03   Driver Version: 470.141.03   CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  Off  | 00000000:01:00.0  On |                  N/A |
|  0%   33C    P8    11W / 120W |    528MiB /  6070MiB |      3%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+
```

- コンテナの停止
```
$ docker-compose down
```

- GUIの動作確認
dockerコンテナ内でrvizを起動し、画面が表示さればokです
```
$ rviz2

もしrviz2コマンドが見つからないと言われたら、先に以下を実行して下さい
$ source /opt/ros/humble/setup.sh 
```

# 参考
- [[公式]NVIDIA Container Toolkitのインストールガイド](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)
- [[公式]Docker CompoesでのGPU使用](https://docs.docker.jp/compose/gpu-support.html)
- [NVIDIA Container Toolkit (NVIDIA Docker) は何をしてくれるか](https://qiita.com/tkusumi/items/f275f0737fb5b261a868)