462 lines
12 KiB
Markdown
462 lines
12 KiB
Markdown
# 85 · Docker 容器化开发(完全指南)
|
|
|
|
> **目标**:吃透本仓库 Docker 配置,知道每行在做什么,能改能扩,能在 Win/macOS/Linux 一致跑 ROS2。
|
|
|
|
---
|
|
|
|
## 目录
|
|
|
|
- [1. 为什么用 Docker](#1-为什么用-docker)
|
|
- [2. 镜像构建](#2-镜像构建)
|
|
- [3. 容器编排](#3-容器编排)
|
|
- [4. 容器生命周期命令](#4-容器生命周期命令)
|
|
- [5. 一键启动脚本](#5-一键启动脚本)
|
|
- [6. 调试技巧](#6-调试技巧)
|
|
- [7. 常见坑](#7-常见坑)
|
|
- [8. 多机 / 多机器人扩展](#8-多机--多机器人扩展)
|
|
- [9. 在本仓库里跑](#9-在本仓库里跑)
|
|
- [10. 进阶:多阶段构建 + 镜像瘦身](#10-进阶多阶段构建--镜像瘦身)
|
|
|
|
---
|
|
|
|
## 1. 为什么用 Docker
|
|
|
|
| 痛点 | Docker 怎么解 |
|
|
|---|---|
|
|
| Linux/Windows/macOS 行为差异 | 镜像固定 Linux,行为一致 |
|
|
| ROS2 apt 装一堆,污染系统 | 容器内隔离 |
|
|
| 团队协作"在我机器能跑" | 镜像统一 |
|
|
| 升级 ROS 版本代价大 | 换镜像就行 |
|
|
| 跨语言/多版本测试 | 同一镜像多容器 |
|
|
|
|
本仓库基于 **`osrf/ros:humble-desktop`**(OSRF 官方维护):
|
|
|
|
- ROS2 Humble 完整运行时
|
|
- 默认 RMW: `rmw_fastrtps_cpp`
|
|
- 自带 RViz2 / rqt / colcon / rosdep
|
|
|
|
---
|
|
|
|
## 2. 镜像构建
|
|
|
|
### 2.1 Dockerfile
|
|
|
|
[`docker/Dockerfile`](../docker/Dockerfile) 在 `osrf/ros:humble-desktop` 之上加:
|
|
|
|
```dockerfile
|
|
FROM osrf/ros:humble-desktop
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
ENV ROS_DISTRO=humble
|
|
ENV WORKSPACE=/root/ros2_ws
|
|
|
|
RUN apt-get update && apt-get install -y \
|
|
python3-colcon-common-extensions \
|
|
python3-pip \
|
|
nano \
|
|
curl \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
RUN pip3 install -U colcon-argcomplete colcon-common-extensions
|
|
|
|
RUN echo 'source /opt/ros/humble/setup.bash' >> /root/.bashrc && \
|
|
echo 'source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash' >> /root/.bashrc
|
|
|
|
WORKDIR ${WORKSPACE}
|
|
|
|
CMD ["bash"]
|
|
```
|
|
|
|
### 2.2 构建
|
|
|
|
```powershell
|
|
# Windows
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml build
|
|
```
|
|
|
|
```bash
|
|
# Linux
|
|
docker compose -p ros2 -f docker/docker-compose.yml build
|
|
```
|
|
|
|
镜像名:`ros2-humble-dev:latest`,约 3GB。
|
|
|
|
### 2.3 镜像内已装
|
|
- ROS2 Humble Desktop
|
|
- `colcon-common-extensions` + `colcon-argcomplete`
|
|
- `cv_bridge` (openCV ↔ ROS Image)
|
|
- `ros-humble-tf2-tools` (`view_frames`)
|
|
- `ros-humble-robot-state-publisher` (URDF → TF)
|
|
|
|
**未装**(按需补):
|
|
- `ros-humble-rmw-cyclonedds-cpp`(默认 fastdds 够用)
|
|
- `ros-humble-ros2-control`
|
|
- `ros-humble-moveit`
|
|
- `ros-humble-navigation2`
|
|
|
|
### 2.4 修改镜像(自定义)
|
|
|
|
加包:在 `apt-get install` 加一行:
|
|
```dockerfile
|
|
RUN apt-get install -y ros-humble-ros2-control ros-humble-ros2-controllers
|
|
```
|
|
|
|
加 Python 包:
|
|
```dockerfile
|
|
RUN pip3 install ultralytics==8.0.0 numpy==1.26
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 容器编排
|
|
|
|
### 3.1 docker-compose.yml
|
|
|
|
[`docker/docker-compose.yml`](../docker/docker-compose.yml):
|
|
|
|
```yaml
|
|
name: ros2 # 独立 compose project(脱离默认 docker 分组)
|
|
|
|
services:
|
|
ros2:
|
|
build: .
|
|
image: ros2-humble-dev:latest
|
|
container_name: ros2_dev
|
|
|
|
privileged: true # 调试用
|
|
stdin_open: true # docker exec -it
|
|
tty: true
|
|
|
|
networks: # 自定义 bridge(脱离 docker_default)
|
|
ros2_net:
|
|
ipv4_address: 172.20.0.10 # 固定 IP,便于 ROS_STATIC_PEERS
|
|
|
|
environment:
|
|
- ROS_DOMAIN_ID=0
|
|
# 不要设 RMW_IMPLEMENTATION=rmw_cyclonedds_cpp:
|
|
# 镜像没装 cyclone dds,CMake 配置会失败。
|
|
- RCUTILS_COLORIZED_OUTPUT=1
|
|
|
|
volumes:
|
|
- ..:/root/ros2_ws # bind mount 本机 D:\xs\ros2
|
|
|
|
working_dir: /root/ros2_ws
|
|
|
|
command: ["bash", "-lc", "tail -f /dev/null"] # 容器永不退
|
|
|
|
networks:
|
|
ros2_net:
|
|
driver: bridge
|
|
ipam:
|
|
config:
|
|
- subnet: 172.20.0.0/24
|
|
gateway: 172.20.0.1
|
|
```
|
|
|
|
### 3.2 为什么自定义 bridge 而不是 host network
|
|
|
|
ROS2 默认用 DDS multicast 在同一网段自动发现节点。
|
|
**默认 docker bridge 网络会拦截 multicast**,导致容器内节点看不见彼此。
|
|
|
|
本仓库选择**自定义 bridge**(`ros2_net`,子网 `172.20.0.0/24`),原因:
|
|
- 跟系统 `docker_default` 隔离,不让无关容器"窜"进 ROS 节点组
|
|
- 容器固定 IP(`172.20.0.10`),便于 `ROS_STATIC_PEERS` 配置
|
|
- bridge 内 multicast 在同一 docker 网络内**能正常通**——本仓库默认 fastdds + 单机场景下,所有节点都在 `ros2_dev` 容器里,bridge 完全够用
|
|
|
|
如果做**跨主机 ROS2 部署**(PC ↔ RDK X5 ↔ RK3506,见 `100-embedded-deployment.md`),需要 `network_mode: host` 或 host gateway。
|
|
|
|
### 3.3 为什么 bind mount 整个工程
|
|
|
|
`..` 是 docker-compose.yml 的上一级(`D:\xs\ros2`)。挂到容器内
|
|
`/root/ros2_ws`,**你在 Windows 改代码,容器内 colcon 立即看到**(`--symlink-install`)。
|
|
|
|
---
|
|
|
|
## 4. 容器生命周期命令
|
|
|
|
```powershell
|
|
# 构建镜像
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml build
|
|
|
|
# 启动(后台)
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml up -d
|
|
|
|
# 状态
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml ps
|
|
|
|
# 进开发终端(必须先 source ROS2 + 本项目 install)
|
|
docker exec -it ros2_dev bash -lc "source /opt/ros/humble/setup.bash && source /root/ros2_ws/install/setup.bash && exec bash"
|
|
|
|
# 一次性跑命令
|
|
docker exec ros2_dev bash -lc "cd /root/ros2_ws && colcon build --packages-select py_pubsub"
|
|
|
|
# 关
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml down
|
|
|
|
# 重启
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml restart
|
|
|
|
# 删容器(保留镜像)
|
|
docker compose -p ros2 -f D:\xs\ros2\docker\docker-compose.yml down
|
|
|
|
# 删镜像
|
|
docker rmi ros2-humble-dev:latest
|
|
|
|
# 看日志
|
|
docker logs -f ros2_dev
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 一键启动脚本
|
|
|
|
本仓库的所有"一键"命令都在 `scripts/` 目录下,**没有**项目根的 `start.ps1` /
|
|
`start.sh` / `build.sh`(老文档里残留的引用一律作废,统一指向 `scripts/`)。
|
|
|
|
### 5.1 进入开发终端(交互式 shell)
|
|
```bash
|
|
bash scripts/shell.sh
|
|
```
|
|
等价于:
|
|
- `docker ps` 看容器是否在跑
|
|
- 如果没跑 → 自动 `docker run -d -it ... ros2-humble-dev:latest bash` 启起来
|
|
- `docker exec -it ros2_dev bash -lc "source /opt/ros/humble/setup.bash && source /root/ros2_ws/install/setup.bash && cd /root/ros2_ws && exec bash"`
|
|
|
|
### 5.2 编译 12 个包(容器内)
|
|
```bash
|
|
bash scripts/build.sh
|
|
```
|
|
等价于:
|
|
```bash
|
|
source /opt/ros/humble/setup.bash
|
|
cd /root/ros2_ws
|
|
colcon build --symlink-install --executor sequential \
|
|
--packages-select <12 个包>
|
|
```
|
|
|
|
> ❗ **`--executor sequential` 必需**。colcon 默认 parallel,12 个包并行构建
|
|
> 时 `cpp_custom_interface` 的 rosidl export cmake 会偶发 CMake 报错。
|
|
> 串行构建 100% 稳定。详见 `doc/80-package-build.md`。
|
|
|
|
### 5.3 跑所有测试
|
|
```bash
|
|
bash scripts/test.sh
|
|
```
|
|
等价于 `colcon test --executor sequential --packages-select <12 个包>` + `colcon test-result --all`。
|
|
|
|
### 5.4 跑 launch demo
|
|
```bash
|
|
bash scripts/launch.sh pubsub_launch 30 # 跑 30 秒自动停
|
|
bash scripts/launch.sh full_demo_launch -1 # -1 = 一直跑(后台)
|
|
```
|
|
|
|
### 5.5 清理构建产物
|
|
```bash
|
|
bash scripts/clean.sh # 等价于 rm -rf build install log
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 调试技巧
|
|
|
|
### 6.1 看容器日志
|
|
```bash
|
|
docker logs ros2_dev
|
|
docker logs -f ros2_dev # 持续
|
|
```
|
|
|
|
### 6.2 进容器交互 shell
|
|
```bash
|
|
docker exec -it ros2_dev bash
|
|
# 进入后:
|
|
source /opt/ros/humble/setup.bash
|
|
cd /root/ros2_ws
|
|
source install/setup.bash
|
|
```
|
|
|
|
### 6.3 在容器内单次跑命令
|
|
```bash
|
|
docker exec ros2_dev bash -lc "source /opt/ros/humble/setup.bash && ros2 node list"
|
|
```
|
|
|
|
### 6.4 看 DDS 流量
|
|
```bash
|
|
docker exec ros2_dev bash -lc "source /opt/ros/humble/setup.bash && ros2 doctor --report"
|
|
```
|
|
|
|
### 6.5 看网络
|
|
```bash
|
|
docker exec ros2_dev bash -lc "ip addr; ip route"
|
|
```
|
|
|
|
### 6.6 容器与宿主机共享 GPU(可选)
|
|
```yaml
|
|
services:
|
|
ros2:
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
```
|
|
|
|
---
|
|
|
|
## 7. 常见坑
|
|
|
|
### 7.1 容器启动后找不到 ros2 命令
|
|
容器里 `/opt/ros/humble/setup.bash` 没 source。每个 shell 都要 source,
|
|
或者写进 `~/.bashrc`(已加,新 bash 自动 source)。
|
|
|
|
### 7.2 改了源码但 colcon 看不到
|
|
确认 `--symlink-install`(默认配置里加上了)。否则需要重 build。
|
|
|
|
### 7.3 跨容器看不到节点
|
|
- 同一 ROS Domain(`ROS_DOMAIN_ID`)
|
|
- host network(本仓库用了)
|
|
- multicast 没被拦截
|
|
|
|
### 7.4 Windows bind mount 文件锁
|
|
有时 LSP / IDE 持文件锁,导致容器内 colcon 失败。关掉 IDE 或在容器内编辑。
|
|
|
|
### 7.5 容器启动很慢
|
|
- Docker Desktop 未运行
|
|
- WSL2 后端未启用
|
|
- 镜像太大(本仓库 ~3GB 正常)
|
|
|
|
### 7.6 容器 OOM
|
|
Docker Desktop → Settings → Resources → Memory 调到 ≥ 4GB。
|
|
|
|
---
|
|
|
|
## 8. 多机 / 多机器人扩展
|
|
|
|
```yaml
|
|
# docker-compose.yml 改成:
|
|
services:
|
|
robot1:
|
|
image: ros2-humble-dev:latest
|
|
container_name: ros2_robot1
|
|
network_mode: host
|
|
environment:
|
|
- ROS_DOMAIN_ID=42
|
|
- ROS_NAMESPACE=robot1
|
|
volumes:
|
|
- ./robot1_conf:/root/ros2_ws
|
|
|
|
robot2:
|
|
image: ros2-humble-dev:latest
|
|
container_name: ros2_robot2
|
|
network_mode: host
|
|
environment:
|
|
- ROS_DOMAIN_ID=42
|
|
- ROS_NAMESPACE=robot2
|
|
volumes:
|
|
- ./robot2_conf:/root/ros2_ws
|
|
|
|
central:
|
|
image: ros2-humble-dev:latest
|
|
container_name: ros2_central
|
|
network_mode: host
|
|
environment:
|
|
- ROS_DOMAIN_ID=42
|
|
command: ["bash", "-lc", "ros2 launch bringup multi_robot_launch.py"]
|
|
```
|
|
|
|
每个 container 各跑一组节点,`ROS_NAMESPACE` 隔离命名空间,
|
|
`ROS_DOMAIN_ID` 共享同一总线 → 跨容器通讯。
|
|
|
|
详见 [`doc/100-embedded-deployment.md`](100-embedded-deployment.md)。
|
|
|
|
---
|
|
|
|
## 9. 在本仓库里跑
|
|
|
|
### 9.1 一键启(推荐用 Makefile)
|
|
|
|
```powershell
|
|
make build # 首次构建镜像
|
|
make up # 后台启动容器
|
|
make shell # 进入开发终端(自动 source ROS2 + install)
|
|
make colcon-build # 编译 12 包
|
|
make colcon-test # 跑 82 测试
|
|
make full-demo # 跑 11 节点 full_demo
|
|
```
|
|
|
|
### 9.2 进入后跑测试
|
|
|
|
```bash
|
|
bash scripts/test.sh # 推荐:自带 --executor sequential
|
|
```
|
|
|
|
### 9.3 跑 demo
|
|
|
|
```bash
|
|
docker exec ros2_dev bash -lc "source /opt/ros/humble/setup.bash && source /root/ros2_ws/install/setup.bash && ros2 launch bringup full_demo_launch.py"
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 进阶:多阶段构建 + 镜像瘦身
|
|
|
|
### 10.1 当前镜像大小
|
|
|
|
```bash
|
|
docker images ros2-humble-dev
|
|
# SIZE: 3.4GB
|
|
```
|
|
|
|
来源:
|
|
- `osrf/ros:humble-desktop`: ~2.1GB(包含 RViz / rqt / Gazebo)
|
|
- 我们的 apt 包 + colcon: ~1.3GB
|
|
|
|
### 10.2 改用 `osrf/ros:humble-ros-base`
|
|
|
|
基础镜像改成 `humble-ros-base`(无 RViz / rqt):
|
|
```dockerfile
|
|
FROM osrf/ros:humble-ros-base
|
|
```
|
|
**SIZE 减少 ~1.5GB**。但少了 RViz / rqt / Gazebo,如果需要这些再加 apt。
|
|
|
|
### 10.3 多阶段构建(进一步瘦身)
|
|
|
|
```dockerfile
|
|
# Stage 1: build
|
|
FROM osrf/ros:humble-ros-base AS builder
|
|
# ... 装 build 工具,build 我们的包 ...
|
|
|
|
# Stage 2: runtime
|
|
FROM osrf/ros:humble-ros-base
|
|
COPY --from=builder /root/ros2_ws/install /root/ros2_ws/install
|
|
# 不带 build 工具,更小
|
|
```
|
|
|
|
适合 CI 流水线 + 生产环境。
|
|
|
|
---
|
|
|
|
## 接下来读
|
|
|
|
| 主题 | 文档 |
|
|
|---|---|
|
|
| venv 工作流 | [`02-virtualenv.md`](02-virtualenv.md) |
|
|
| 测试策略 | [`90-testing.md`](90-testing.md) |
|
|
| 三机部署 | [`100-embedded-deployment.md`](100-embedded-deployment.md) |
|
|
| 项目总览 | [`00-overview.md`](00-overview.md) |
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## 📖 阅读路径导航
|
|
|
|
> 💡 这是仓库 `doc/` 下所有文档的推荐阅读顺序。[返回 README 总导航](../README.md#-23-篇文档怎么读)
|
|
>
|
|
> ⏱ **本文预计阅读时间**: 40 分钟
|
|
> 📍 **当前位置**: 第 20 / 24 篇
|
|
|
|
- ⏮ **上一篇**: [colcon / ament 包构建](80-package-build.md)
|
|
- ⏭ **下一篇**: [测试金字塔](90-testing.md)
|