3. 开发环境搭建:使用Docker和DevContainer搭建可复现的ROS2 Humble开发环境
说实话,我见过太多团队在环境配置上栽跟头了。
「在我机器上能跑啊」——这句话,几乎是每个机器人工程师的噩梦。我自己就经历过:项目做到一半,同事换了台电脑,结果依赖库版本对不上,整整浪费了两天去排查。从那以后,我下定决心,必须用容器化方案来统一开发环境。
今天我们就来聊聊,怎么用Docker和DevContainer,搭建一个可复现的ROS2 Humble开发环境。
为什么非要用容器?
你想想看,ROS2的依赖有多复杂?Python包、C++库、系统工具链、还有各种硬件驱动。每个人装的方式不一样,系统版本不一样,迟早出问题。
容器化开发的好处很明显:
- 环境一致:你、我、他,拉下来跑起来,一模一样
- 快速重建:搞坏了?删了重来,三分钟搞定
- 版本控制:Dockerfile写进Git,环境变更可追溯
- 隔离干净:不污染宿主机,一个项目一个容器
核心思路:把开发环境当作代码来管理。Dockerfile就是环境的「源代码」,镜像就是「编译产物」。
方案一:纯Docker镜像
这是最直接的方式。我早期做项目时就用这个,简单粗暴。
编写Dockerfile
先看一个基础版:
FROM ros:humble-ros-base-jammy
# 安装常用工具
RUN apt-get update && apt-get install -y \
vim \
git \
curl \
wget \
python3-pip \
python3-colcon-common-extensions \
&& rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /workspace
# 设置环境变量
ENV ROS_DOMAIN_ID=42
# 默认命令
CMD ["/bin/bash"]
嗯,这里要注意一点:rm -rf /var/lib/apt/lists/* 这行不能省。我见过有人没加,结果镜像体积直接翻倍。Docker镜像每层都是增量存储,apt缓存不清掉,会一直留在里面。
构建与运行
# 构建镜像
docker build -t ros2-humble-dev .
# 运行容器(带GUI支持)
docker run -it --rm \
--name ros2_dev \
--network host \
--env DISPLAY=$DISPLAY \
--volume /tmp/.X11-unix:/tmp/.X11-unix:rw \
--volume $(pwd):/workspace \
ros2-humble-dev
小技巧:如果你需要可视化(比如rviz2),记得加上 --network host 和X11转发。我刚开始忘了加,rviz2死活打不开,折腾了半天才发现是网络模式的问题。
方案二:DevContainer(推荐)
说实话,纯Docker方案有个痛点:每次都要手动敲docker run命令,参数一长串,很容易漏。而且VS Code的远程开发插件没法直接对接。
DevContainer就是来解决这个问题的。它是VS Code的一个扩展,让你直接在容器里写代码、调试、运行终端。
项目结构
我习惯在项目根目录下建一个 .devcontainer 文件夹:
my_ros2_project/
├── .devcontainer/
│ ├── devcontainer.json
│ └── Dockerfile
├── src/
│ └── ...
├── .gitignore
└── README.md
配置devcontainer.json
{
"name": "ROS2 Humble Dev",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"runArgs": [
"--network=host",
"--env=DISPLAY=${env:DISPLAY}",
"--volume=/tmp/.X11-unix:/tmp/.X11-unix:rw"
],
"mounts": [
"source=${localWorkspaceFolder}/src,target=/workspace/src,type=bind"
],
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"ms-python.python",
"twxs.cmake",
"ms-iot.vscode-ros"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"cmake.configureOnOpen": true
}
}
},
"postCreateCommand": "rosdep update && colcon build"
}
这里有个坑,我踩过:postCreateCommand 里如果直接跑 colcon build,第一次构建会很久。建议先只装依赖,等容器启动后再手动构建。或者把构建命令拆成两步。
Dockerfile(增强版)
FROM ros:humble-ros-base-jammy
# 安装开发工具
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
python3-colcon-common-extensions \
python3-rosdep \
python3-vcstool \
&& rm -rf /var/lib/apt/lists/*
# 初始化rosdep
RUN rosdep init && rosdep update
# 安装常用ROS2包
RUN apt-get update && apt-get install -y \
ros-humble-rviz2 \
ros-humble-gazebo-ros-pkgs \
ros-humble-nav2-* \
&& rm -rf /var/lib/apt/lists/*
# 创建非root用户(安全考虑)
RUN useradd -m -s /bin/bash rosuser \
&& echo "rosuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER rosuser
WORKDIR /workspace
注意:生产环境中,我强烈建议创建一个非root用户。虽然开发时用root方便,但一旦容器要部署到生产环境,root权限就是个安全隐患。我曾经见过一个团队,因为容器里一直用root,结果CI/CD流水线被攻破,整个镜像仓库都被污染了。
方案三:多阶段构建(进阶)
如果你的项目比较大,或者需要交叉编译,多阶段构建是个好选择。
# 第一阶段:构建阶段
FROM ros:humble-ros-base-jammy AS builder
COPY src/ /workspace/src
WORKDIR /workspace
RUN rosdep install --from-paths src --ignore-src -r -y \
&& colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
# 第二阶段:运行阶段
FROM ros:humble-ros-base-jammy
COPY --from=builder /workspace/install /workspace/install
COPY --from=builder /workspace/src /workspace/src
WORKDIR /workspace
CMD ["ros2", "launch", "my_project", "start.launch.py"]
这样做的好处是:最终镜像只保留运行所需的文件,构建工具链全部丢弃。镜像体积能缩小60%以上。我有个项目,原本镜像1.2GB,用多阶段构建后只剩400MB。
避坑指南
这些年用Docker做ROS2开发,我总结了几条经验:
- 网络问题:国内拉取ros镜像慢?用镜像加速器。我一般用阿里云的,速度还不错。
- 权限问题:容器里创建的文件,宿主机上可能属于root。解决方案是在docker run时指定用户ID:
--user $(id -u):$(id -g) - GPU支持:如果你要用CUDA,记得加
--gpus all参数,并且用nvidia/cuda作为基础镜像。 - 时间同步:容器时间默认是UTC,和宿主机不一致。加
--volume /etc/localtime:/etc/localtime:ro解决。
我的习惯:每个项目都配一个 Makefile,把常用的docker命令封装起来。比如 make build、make run、make clean。这样团队里任何人,只要敲几个字母就能开始干活。
验证环境
搭建完了,怎么确认环境没问题?我一般跑几个测试:
# 检查ROS2版本
ros2 --version
# 测试话题通信
ros2 run demo_nodes_cpp talker &
ros2 run demo_nodes_cpp listener
# 检查colcon
colcon --version
# 检查Python
python3 -c "import rclpy; print('rclpy OK')"
如果这些都能跑通,恭喜你,环境搭建成功了。
最后说一句:环境搭建看似基础,但它是整个项目的基石。花点时间把这一步做好,后面能省下无数麻烦。我个人习惯,每个新项目都会先花半天时间把DevContainer配好,然后把这个配置提交到Git仓库。这样不管谁来接手,都能立刻进入开发状态。
下一章,我们会在这个环境里,开始写第一个ROS2节点。准备好了吗?