# ai_robot_dockerizer **Repository Path**: katly/ai_robot_dockerizer ## Basic Information - **Project Name**: ai_robot_dockerizer - **Description**: 私有仓库,单独维护。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-20 - **Last Updated**: 2025-03-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # AI Robot Dockerizer AI Robot Dockerizer 是一个用于 AI Robot 项目Docker 镜像构建的自动化工具,为项目开发、测试和部署提供容器化支持。 ## 为什么不直接使用 ROS 官方 Docker 镜像 尽管 ROS 社区提供了[官方 Docker 镜像](https://hub.docker.com/_/ros/),但它存在以下局限: - Ubuntu 系统软件仓库源默认为境外站点,安装系统软件包时速度慢; - ROS 官方软件仓库源为境外站点,安装 ROS 相关软件包时速度慢; - 镜像中只有 root 用户,无法以普通用户权限运行容器,易导致主机和容器间共享资源的权限问题; - 不包含基于 NVIDIA 的 OpenGL 支持,导致部分依赖 OpenGL 的图形化应用无法正常运行; - 不包含 CUDA/cuDNN 支持,可能无法运行一些使用 GPU 加速的 AI 应用; - 如果使用 ROS Melodic,则 Ubuntu 18.04 的 CMake 版本太老,可能无法构建一些较新的第三方项目。 ## 分层设计 本工具将镜像构建分为三个阶段,分别是: 1. 基于 Ubuntu 系统构建 ROS 基础镜像; 2. 基于 ROS 基础镜像构建具有普通用户权限的用户镜像; 3. 基于用户镜像构建面向 AI Robot 开发或发布的应用镜像。 ### ROS 基础镜像 与 ROS 官方 Docker 镜像相比,本工具构建的 ROS 镜像具有如下改进: - 将 Ubuntu 系统软件包仓库设定为 SJTU 镜像站点以加速系统软件包安装; - 将 ROS 软件包仓库设定为 SJTU 镜像站点以加速 ROS 软件包安装; - 集成 `su-exec` 命令用于支持以普通用户权限运行容器; - 安装 *catkin_tools* 作为 ROS 应用的默认构建工具; - 支持 NVIDIA OpenGL; - 可选择性地集成 CUDA 和 cuDNN 运行时或开发工具包。 ROS 社区按照不同的“角色”划分(见 [REP-142](https://www.ros.org/reps/rep-0142.html)) 对 ROS 进行打包,提供了 *Core*、*Base*、*Robot*、*Desktop* 和 *Desktop Full* 五种级别的 ROS 系统安装包以及对应的 Docker 镜像,但本工具目前仅提供 *Base*、*Desktop* 和 *Desktop Full* 三种级别的 ROS 镜像构建。 ### 用户镜像 用户镜像基于 ROS 基础镜像,进行了如下扩展: - 创建 `render` 组; - 创建 `uav` 用户(UID 和 GID 均为 `1000`),并将 `uav` 用户分别加入 `sudo`、`audio`、`video` 和 `render` 组; - 通过 `/etc/sudoers.d/uav` 文件为 `uav` 用户设定 `sudo` 权限; - 创建 `/home/uav/.config` 目录,并将其所有权(ownership)设定为 `uav:uav`; - 将定制的 entrypoint 脚本安装到 `/usr/local/bin/scripts/` 目录下; - 创建 `/home/uav/catkin_ws` 目录作为 ROS 工作空间,并将容器内的默认工作目录(`WORKDIR`)切换到该目录。 ### 应用镜像 应用镜像构建于用户镜像之上,本工具定义了两种应用镜像类型:**开发类**(**devel**)镜像和**发布类**(**release**)镜像。 开发类镜像中安装了用于项目构建和测试的所有依赖,而发布类镜像中只安装了项目构建后的结果以及运行时依赖。开发类镜像不会将项目源码安装到镜像中,而是在容器运行时将主机上的项目源码目录挂载到容器中,这样无论是在主机上还是在容器中对源码的修改都会立刻同步到另一端。 在构建过程中,无论是哪一种类型的镜像,均需要指定项目所在的工作区路径,因为构建脚本会使用 `rosdep` 命令遍历工作区中所有 ROS 软件包的 `package.xml` 文件来获取所需的依赖列表并安装这些依赖。因此,正确书写项目中每一个 ROS 软件包的 `package.xml` 极为重要! 对于无法使用 `rosdep` 安装的其他依赖,本工具也提供了一套使用 Shell 脚本进行扩展的简单机制。 发布类镜像的构建首先需要基于开发类镜像创建一个中间镜像用于从源码构建项目,在从中间镜像中将构建结果复制到发布类镜像中。因此,正确书写每一个 ROS 软件包的 `CMakeLists.txt` 也至关重要,尤其要注意其中的 `install` 目标是否完整。同时,应当合理设计每一个 ROS 软件包的结构布局,以确保它们可以脱离源码目录正确运行。 下图粗略描述了一个 AI Robot 应用镜像的构建步骤: ```mermaid graph TD BEG([开始]) --> ROS ROS[构建一个可选择集成 CUDA/cuDNN 运行时或完整开发工具包的 ROS 镜像] ROS --> BASEONLY{"是否仅构建基础 ROS 镜像?"} BASEONLY -->|Yes| BASEIMG[\基础 ROS 镜像\] --> END([结束]) BASEONLY -->|No| USER[基于 ROS 镜像构建一个拥有名为 'uav' 普通帐号的用户镜像] USER --> TYPE{目标镜像类型} TYPE -->|devel| C["构建“开发类”应用镜像"] --> DEVIMG[\"“开发类”应用镜像"\] DEVIMG --> END TYPE -->|release| REL["构建“发布类”应用镜像"] --> RELIMG[\"“发布类”应用镜像"\] TYPE -->|release| INTERMD["构建一个“开发类”中间镜像"] INTERMD --> BUILDER["基于“开发类”临时镜像构建一个用于项目构建的中间镜像并在该镜像生成的容器总构建指定项目"] BUILDER -->|复制构建结果| RELIMG RELIMG --> END BUILDER --> CLEAN[清理中间镜像] ``` ## 依赖 - Bash - Make - Docker Engine 即 *docker-ce*、*docker-cli* - (可选)NVIDIA 闭源驱动(安装到主机上而非镜像中) - (可选)NVIDIA Container Toolkit(只支持 Ubuntu 18.04/20.04/22.04 LTS,必须有 NVIDIA 闭源驱动配合) Bash 是主流 Linux 发行版标配,Make 和 NVIDIA 闭源驱动可使用系统包管理器进行安装。Docker Engine 和 NVIDIA Container Toolkit,推荐使用 `scripts/docker_install` 进行安装。 ## 辅助脚本 构建支持 NVIDIA GPU 加速的 Docker 镜像以及以普通用户权限运行支持图形化功能的 Docker 容器,需要较多复杂的设置。 为此,本工具在 `scripts` 目录下提供了三个 Shell 辅助脚本以简化操作流程: - `scripts/dokcer_install`:用于安装 Docker Engine 和 NVIDIA Container Toolkit。 - `scripts/docker_build`:对 `docker build` 命令的封装,用于构建 Docker 镜像。 - `scripts/docker_run`:对 `docker run` 命令的封装,用于运行 Docker 容器。 这三个脚本能覆盖 ROS 应用开发的一般场景,无需用户编写 Dockerfile。对于更复杂的使用场景和工作流程,用户也可以使用本工具来构建 ROS 基础镜像,再基于基础镜像自行编写 Dockerfile 进行扩展。 ## 使用方法 三个辅助脚本均支持命令行选项,可通过 `--help` 选项来查看它们的使用帮助。以下仅以一些典型用例加以说明。 ### 安装容器引擎 NVIDIA Container Toolkit 提供了 NVIDIA 实现的 Linux 容器运行时(container runtime),以支持在容器中访问主机上的 NVIDIA GPU 设备驱动。如果主机未加装 NVIDIA GPU,或者是未使用 NVIDIA 闭源驱动,则无需安装 NVIDIA Container Toolkit。`docker_install` 脚本的使用方法如下: ```sh # 查看使用帮助 scripts/docker_install --help # 仅安装 Docker Engine scripts/docker_install # 同时安装 Docker Engine 和 NVIDIA Container Toolkit scripts/docker_install --nv # 仅安装 NVIDIA Container Toolkit(Docker Engine 已安装) scripts/docker_install --nv-only ``` ### 设置代理(可选) 在构建 ROS Docker 镜像的过程中,构建脚本需执行 `rosdep init` 命令。该命令会从 Github 下载若干 YAML 文件以获取ROS 软件包和系统软件包之间的映射和依赖关系,因此你很可能需要使用网络代理来解决 Github 访问超时问题。 值得注意的是,Docker 引擎并不遵照系统的网络代理设置,而是自行实现了一套独立的代理机制。我们可以通过修改 `~/.docker/config.json` 配置文件来为 Docker 设置代理。将以下内容添加到该配置文件中,并把其中的 `://:` 部分替换成你自己的设置: ```json { "proxies": { "default": { "httpProxy": "socks5://127.0.0.1:7890", "httpsProxy": "socks5://127.0.0.1:7890", "noProxy": ".docker.io,.aliyun.com,.163.com,ubuntu.com,.edu.cn,.nvidia.cn,.nvidia.com,127.0.0.0/8,192.168.0.0/16" } } } ``` `noProxy` 定义了哪些域名或 IP 不走代理,通常包括 Docker Hub 站点及其国内镜像,Ubuntu 系统的软件源,NVIDIA 相关站点,以及一些常见局域网 IP 等。如果你需要绕过代理访问一些额外的站点,请自行将它们添加到该列表中。此外,一些网络代理客户端也可以自定义代理规则。总之,Docker 镜像构建可能下载大量数据,请务必设定好代理规则,以免在一些访问不受限的站点上浪费代理流量。 ### 构建“开发类”镜像 使用 `scripts/docker_build` 来构建镜像。如果仅想要查看该脚本将要执行的动作,而不实际执行它门,则可以使用 `--dry-run` 选项。 假设一个 ROS 应用项目的工作区路径为 `~/workspaces/ai_robot_ws/`, 下面这条命令可以为该项目构建一个集成 CUDA 11.7.1 和 cuDNN 8 运行时的 ROS Noetic Desktop Full 开发类镜像: ```sh scripts/docker_build --cuda 11.7.1 --cudnn 8 --type devel --tag batc/ai_robot:noetic-desktop-full_cuda11.7.1-cudnn8-rt_dev noetic-desktop-full ~/workspace/ai_robot_ws ``` 其中,`noetic-desktop-full` 指定了 ROS 的版本(distro)和角色(role),该角色包含完整的图形化工具和仿真工具;`~/workspace/ai_robot_ws` 指定了目标项目在主机上的工作区目录;`--tag` 选线指定了镜像名称(标签),命名规则一般遵循 Docker Hub 规则,即 `/:`,`` 部分应能说明该镜像的关键属性;`--type` 选项指定了镜像类型,如果省略该选项,则默认为 `devel`。 镜像构建的实际过程大体是:构建 ROS neotic-desktop-full 基础镜像(集成 CUDA 11.7.1 和 cuDNN 8 运行时)-> 构建 ROS 用户镜像 -> 构建用于指定项目的开发类镜像。 如果你的项目不仅需要 CUDA 和 cuDNN 运行时,还需要开发工具包(包含头文件、编译器等)以支持 CUDA 应用的源码编译,则需使用 `--cuda-dev` 选项: ```sh scripts/docker_build --cuda 11.7.1 --cudnn 8 --cuda-dev --type devel --tag batc/ai_robot:noetic-desktop-full_cuda11.7.1-cudnn8-dev_dev noetic-desktop-full ~/workspace/ai_robot_ws ``` 如果你的项目仅需要 NVIDIA GPU 的 OpenGL 支持,无需 CUDA 或是通过其他途径安装 CUDA(例如使用 `pip` 安装 PyTorch 会自行安装 CUDA Toolkit),那么使用 `--nv` 选项即可: ```sh scripts/docker_build --nv --type devel --tag batc/ai_robot:noetic-desktop-full_nvidia_dev noetic-desktop-full ~/workspace/ai_robot_ws ``` 如果你的主机没有 NVIDIA GPU,则无需使用 NVIDIA 相关选项: ```sh scripts/docker_build --type devel --tag batc/ai_robot:noetic-desktop-full_dev noetic-desktop-full ~/workspace/ai_robot_ws ``` **注意**:本工具构建的 ROS 镜像无法支持也不可能支持所有版本的 CUDA 和 cuDNN,对于当前支持的 ROS 版本 和 CUDA/cuDNN 版本组合,可通过以下命令查看: ```sh scripts/docker_build --ls-base ``` ### 构建“发布类”镜像 “发布类”镜像的构建与“开发类”镜像的构建类似,一般只需将 `--type` 选项的参数值修改为 `release`,并设定合理的镜像名称(`--tag`)。发布类镜像命名可使用 `_rel` 后缀以表示 `release`,不过当开发类镜像的 `_dev` 后缀足以区分两者时,也可以省去 `_rel` 后缀。 ```sh # ROS noetic-desktop with CUDA 11.7.1 + cuDNN 8 runtime scripts/docker_build --cuda 11.7.1 --cudnn 8 --type release --tag batc/ai_robot:noetic-desktop_cuda11.7.1-cudnn8-rt noetic-desktop ~/workspace/ai_robot_ws # ROS noetic-desktop with NVIDIA OpenGL support scripts/docker_build --nv --type release --tag batc/ai_robot:noetic-desktop_nvidia noetic-desktop ~/workspace/ai_robot_ws # ROS noetic-desktop without NVIDIA support scripts/docker_build --type release --tag batc/ai_robot:noetic-desktop_dev noetic-desktop ~/workspace/ai_robot_ws ``` **注意**:发布类镜像不包含源码、开发包和编译构建工具,因此不支持 `--cuda-dev` 选项。另外,发布类镜像用于产品部署和交付,一般不需要仿真工具,可考虑使用 *Desktop* 替代 *Desktop Full* 以减小镜像大小。 ### 仅构建 ROS 镜像 如果本工具构建的应用镜像无法满足使用场景,则可以仅构建 ROS 基础镜像,并在此基础上自行编写 Dockerfile 以构建特定功能的镜像。仅构建 ROS 基础镜像的方法是使用 `--base-only` 选项: ```sh # ROS noetic-desktop-full with CUDA 11.7.1 + cuDNN runtime scripts/docker_build --base-only --cuda 11.7.1 --cudnn 8 --tag batc/ros:noetic-desktop-full_cuda11.7.1-cudnn8-rt noetic-desktop-full # ROS noetic-desktop-full with CUDA 11.7.1 + cuDNN devel toolkit scripts/docker_build --base-only --cuda-dev --cuda 11.7.1 --cudnn 8 --tag batc/ros:noetic-desktop-full_cuda11.7.1-cudnn8-dev noetic-desktop-full # ROS noetic-desktop-full with NVIDIA OpenGL support scripts/docker_build --base-only --nv --tag batc/ros:noetic-desktop-full_nvidia-rt noetic-desktop-full # ROS noetic-desktop-full without NVIDIA support scripts/docker_build --base-only --tag batc/ros:noetic-desktop-full_nvidia-rt noetic-desktop-full ``` ### 脚本扩展 构建脚本会使用 `rosdep` 命令从工作区中各个 ROS 软件包的 `package.xml` 文件中抓取依赖列表并予以安装。如果还需要安装 `rosdep` 无法覆盖的依赖,或是需要一些额外的配置,则可以通过 `/src/docker/scripts/devel/*.sh` 脚本或 `/src/docker/scripts/release/*.sh` 脚本进行扩展。其中,`/src/docker/scripts/devel` 目录下的脚本文件用于扩展开发类镜像构建,`/src/docker/scripts/release` 目录下的脚本文件用于扩展发布类镜像构建。需要注意的是,所有扩展脚本必须拥有可执行权限。 具体使用可参考下文“简单实例”中的“ROS YOLOv5 应用容器化”部分。 ### 运行容器 使用 `docker_run` 脚本运行容器。开发类容器在运行时需指定项目工作区路径,以便 Docker 能够将工作区从主机挂载到容器中;发布类容器可直接运行。以下是以 `~/workspaces/ai_robot_ws` 作为工作区路径的一些用例: ```sh # 打印使用帮助 scripts/docker_run --help # 运行开发类容器(CUDA+cuDNN 支持),并将主机上的 ~/workspaces/ai_robot_ws 目录挂载到容器中的 `/home/uav/catkin_ws` 目录 scripts/docker_run --nv --ws "~/workspace/ai_robot_ws" batc/ai_robot:noetic-desktop-full_cuda11.7.1-cudnn8-rt_dev # 运行开发类容器(NVIDIA OpenGL 支持),并将主机上的 ~/workspaces/ai_robot_ws 目录挂载到容器中的 `/home/uav/catkin_ws` 目录 scripts/docker_run --nv --ws "~/workspace/ai_robot_ws" batc/ai_robot:noetic-desktop-full_nvidia_dev # 运行开发类容器(无 NVIDIA 支持),并将主机上的 ~/workspaces/ai_robot_ws 目录挂载到容器中的 `/home/uav/catkin_ws` 目录 scripts/docker_run --ws "~/workspace/ai_robot_ws" batc/ai_robot:noetic-desktop-full_dev # 运行发布类容器(CUDA+cuDNN 支持),并在容器中执行 `roslaunch ai_robot_bringup start.launch` 命令 scripts/docker_run --nv batc/ai_robot:noetic-desktop-full_cuda11.7.1-cudnn8-rt roslaunch ai_robot_bringup start.launch # 运行发布类容器(NVIDIA OpenGL 支持),并在容器中执行 `roslaunch ai_robot_bringup start.launch` 命令 scripts/docker_run --nv batc/ai_robot:noetic-desktop-full_nvidia roslaunch ai_robot_bringup start.launch # 运行发布类容器(无 NVIDIA 支持),并在容器中执行 `roslaunch ai_robot_bringup start.launch` 命令 scripts/docker_run batc/ai_robot:noetic-desktop-full roslaunch ai_robot_bringup start.launch # 仅打印生成的 docker run 命令行,但不实际运行容器,常用于检查命令是否正确。 scripts/docker_run --dry-run batc/ai_robot:noetic-desktop-full roslaunch ai_robot_bringup start.launch ``` 如果未指定容器执内行的命令,容器默认执行 `/bin/bash`。 ## 容器化举例 ### ROS YOLOv5 应用容器化 该应用从 ROS Topic 获取图像传感器数据,并使用 YOLOv5 进行物体检测。ROS 工作区路径为 `~/workspaces/ai_ws`,工作区结构如下: ``` ~/workspaces/ai_ws/ |__ src/ |__ ai_robot_objdet/ |__ CMakeLists.txt |__ package.xml |__ data/ | |__ images/ | |__ weights/ |__ launch/ | |__ start.launch |__ nodes/ |__ feed |__ detect ``` `~/workspaces/ai_ws/src/ai_robot_objdet/package.xml` 文件内容如下: ```xml ai_robot_objdet 0.1.0 The ai_robot object detection package. To Do To To TODO https://bat.sjtu.edu.cn catkin cv_bridge ``` 其中,`cv_bridge` 包用于 ROS 图像消息格式与 OpenCV 图像格式之间的相互转换,构建脚本会通过 `rosdep` 命令自动安装。 `~/workspaces/ai_ws/src/ai_robot_objdet/CMakeLists.txt` 文件内容如下: ```cmake cmake_minimum_required(VERSION 3.1) project(ai_robot_objdet) find_package(catkin REQUIRED) catkin_package() catkin_install_python(PROGRAMS nodes/feed nodes/detect DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) ``` 项目编译时,CMake 会将 `nodes/feed` 和 `nodes/detect` 两个 Python文件安装到目标位置(工作区中的 install space)。 该应用使用 `pip` 安装 `yolov5`。`yolov5` 的依赖包括 `torch`(PyTorch),而 `torch` 会自动安装 `nvidia-cuda-runtime-cu11` 和 `nvidia-cudnn-cu11`。因此,针对该应用的 ROS 基础镜像无需事先集成 CUDA 和 cuDNN。此外,该应用只需完成物体检测,无需 ROS 的图形化工具和仿真工具,因此使用 Base 等级的 ROS 镜像即可。 根据脚本扩展机制,我们分别创建 `~/workspaces/ai_ws/src/docker/scripts/devel/deps.sh` 和 `~/workspaces/ai_ws/src/docker/scripts/release/deps.sh` 文件。在本例中,开发类镜像和发布类镜像的扩展脚本恰好具有相同的内容: ```sh #!/bin/bash -e # Creates pip config file to use SJTU mirror for speedup. mkdir /home/uav/.config/pip cat < /home/uav/.config/pip/pip.conf [global] index-url = https://mirror.sjtu.edu.cn/pypi/web/simple [install] trusted-host = mirror.sjtu.edu.cn EOF # Docker image builder runs scripts as 'root', it is necessary to change # ownership of the created files under the home directory of the 'uav' user. # NOTE: here USER_UID and USER_GID are both defined by the image builder, hence # you don't have to and shouldn't define them by yourself. chown -R ${USER_UID}:${USER_GID} /home/uav/.config/pip apt-get update apt-get install -y --no-install-recommends python3-pip # Disable pip cache to reduce image size. pip3 --no-cache-dir pip3 install yolov5 ``` 镜像构建命令如下: ```sh # 构建开发类镜像 scripts/docker_build --nv --type devel --tag batc/ai_robot_objdet:noetic-base_nvidia_dev noetic-base ~/workspaces/ai_ws # 构建发布类镜像 scripts/docker_build --nv --type release --tag batc/ai_robot_objdet:noetic-base_nvidia noetic-base ~/workspaces/ai_ws ``` 启动容器的命令如下: ```sh # 启动开发类容器 scripts/docker_run --nv --ws ~/workspaces/ai_ws batc/ai_robot_objdet:noetic-base_nvidia_dev # 启动发布类容器 scripts/docker_run --nv batc/ai_robot_objdet:noetic-base_nvidia_dev roslaunch ai_robot_objdet start.launch ```