docker
基本操作
1. 拉取镜像 (docker pull)
- 作用: 从镜像仓库 (默认是 Docker Hub) 下载镜像到你的本地机器。
- 语法:
docker pull <仓库名>/<镜像名>:<标签>
<仓库名>
: 可选,如果是 Docker Hub 上的官方镜像或知名镜像,通常可以省略。如果是个人或其他组织的镜像,需要指定,例如osrf/ros
。<镜像名>
: 必须,例如ubuntu
,ros
。<标签>
: 可选,用于指定镜像的版本。如果不指定,默认拉取latest
标签。强烈建议总是指定明确的标签,以保证环境的可复现性。例如ubuntu:22.04
,ros:noetic-ros-base
。
- 示例:
拉取官方的 Ubuntu 22.04 镜像:你会看到 Docker 开始下载镜像的各个层 (layer)。
1
docker pull ubuntu:22.04
拉取 ROS Noetic 的基础镜像 (来自 Open Source Robotics Foundation):(这个镜像会大一些,因为它包含了 ROS Noetic 的核心组件)
1
docker pull ros:noetic-ros-base
2. 查看本地镜像 (docker images)
作用: 列出你本地已经下载的所有镜像。
语法:
docker images
示例: 你会看到类似以下的输出:
1
docker images
1
2
3
4REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 xxxxxxxxxxxx xx weeks ago 77.8MB
ros noetic-ros-base yyyyyyyyyyyy xx weeks ago 1.07GB
hello-world latest zzzzzzzzzzzz xx months ago 13.3kBREPOSITORY
: 镜像所在的仓库名。TAG
: 镜像的标签 (版本)。IMAGE ID
: 镜像的唯一标识符。CREATED
: 镜像创建的时间。SIZE
: 镜像的大小。
3. 运行容器 (docker run)
作用: 使用指定的镜像创建一个新的容器并运行它。这是 Docker 最核心的命令之一。
语法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
常用选项 (OPTIONS):
以下这些选项非常关键:
-it
(交互式 TTY)-i
(--interactive
): 保持标准输入(STDIN)打开,即使没有附加连接。简单说,允许你向容器输入命令。-t
(--tty
): 分配一个伪终端(pseudo-TTY)。这会模拟一个真实的终端,让你可以像在普通 Linux Shell 里一样交互,比如使用 Tab 补全、看到命令提示符等。为什么重要? 你通常需要进入容器的 Shell 环境进行编译、运行节点、调试等操作,
-it
几乎是必备组合。示例: 这个命令会启动一个基于
ubuntu:20.04
镜像的容器,并直接进入容器的bash
Shell。你可以像在普通的 Ubuntu 终端里一样操作。退出 Shell(输入exit
或按Ctrl+D
)后,容器通常会停止。1
docker run -it ubuntu:20.04 bash
--rm
(自动移除)当容器退出时,自动删除容器文件系统。
为什么重要? 每次
docker run
都会创建一个新的容器。如果你只是临时运行一个命令或者进入 Shell 调试,用完就扔,--rm
可以避免产生大量无用的、停止状态的容器,保持 Docker 环境整洁。对于调试和测试非常方便。示例: 当你退出这个
bash
后,这个容器会被彻底删除,docker ps -a
也看不到它了。1
docker run -it --rm ubuntu:20.04 bash
-d
(--detach
) (后台运行)让容器在后台运行,并打印出容器 ID。
为什么重要? 有时候你希望容器作为一个服务在后台持续运行(比如运行一个 ROS Master 或者一个模拟器),而不是占用你的当前终端。
注意: 如果使用
-d
,通常容器需要运行一个长期在前台执行的进程(比如一个 web 服务、一个sleep infinity
或者 ROS 节点),否则容器一启动执行完默认命令(如果该命令会结束)就会立刻退出。示例:
1
2
3
4# 启动一个后台运行的容器,里面无限睡眠 (常用于创建一个长期运行的基础容器)
docker run -d --name my_background_ubuntu ubuntu:20.04 sleep infinity
# 你可以使用 docker exec 进入这个后台运行的容器
docker exec -it my_background_ubuntu bash
--name <container_name>
(指定名称)给容器指定一个易于记忆的名字。如果不指定,Docker 会随机生成一个(比如
vigilant_mclean
)。为什么重要? 有了名字,你可以方便地通过名字来管理容器,比如
docker stop my_slam_container
、docker start my_slam_container
、docker exec -it my_slam_container bash
等。示例:
1
docker run -it --rm --name slam_dev_session ubuntu:20.04 bash
-v
或--volume
(挂载卷) /--mount
(更推荐的挂载方式)将宿主机(你的 Ubuntu 22.04)的目录或文件挂载到容器内部。这是实现代码/数据共享和持久化的关键。
为什么对 SLAM 重要?
- 代码开发: 你可以在宿主机上用你喜欢的 IDE 编辑代码,然后在容器里编译和运行,代码是实时同步的。
- 数据集: SLAM 数据集通常很大,你不需要把它们复制到镜像里,直接挂载宿主机上的数据集目录即可。
- 结果保存: 容器运行产生的结果(地图、轨迹、日志)可以保存到挂载的宿主机目录,容器删除后结果依然存在。
语法 (
-v
):-v <host_path>:<container_path>[:options]
语法 (
--mount
):--mount type=bind,source=<host_path>,target=<container_path>[,readonly]
(bind mount 是最常用的类型,效果类似-v
)示例 (使用
-v
):1
2
3
4# 将宿主机的 ~/slam_ws 目录挂载到容器内的 /root/slam_ws 目录
docker run -it --rm -v ~/slam_ws:/root/slam_ws ubuntu:20.04 bash
# 进入容器后,你在 /root/slam_ws 看到的就是宿主机 ~/slam_ws 的内容
# 在容器内修改 /root/slam_ws/some_file.txt,宿主机的 ~/slam_ws/some_file.txt 也会同步改变示例 (使用
--mount
):--mount
语法更清晰,推荐使用。1
docker run -it --rm --mount type=bind,source=~/slam_ws,target=/root/slam_ws ubuntu:20.04 bash
-p
或--publish
(端口映射)将容器的端口映射到宿主机的端口。格式:
-p <host_port>:<container_port>
。为什么对 SLAM 重要? 如果你在容器里运行了需要网络访问的服务(比如 RViz 的 Web 版本、或者某些算法的监控界面),需要将容器端口暴露给宿主机或其他机器。
示例:
1
2
3# 假设容器内 8080 端口运行了一个 web 服务
docker run -d -p 8888:8080 my_web_service_image
# 现在你可以通过访问宿主机的 8888 端口 (http://localhost:8888) 来访问容器内的 8080 服务对于 ROS: 很多时候直接使用
--net=host
(见下一点) 更方便,避免复杂的端口映射。
--net
或--network
(网络模式)配置容器的网络连接方式。常用模式:
bridge
(默认): 容器有自己独立的网络栈,通过 Docker 网桥连接宿主机。需要端口映射 (p
) 才能从外部访问容器服务。host
: 容器共享宿主机的网络栈。容器直接使用宿主机的 IP 地址和端口,无需端口映射。性能最好,但隔离性差。none
: 容器没有网络连接。
为什么
host
对 SLAM/ROS 重要? ROS 节点间通信、RViz 连接 ROS Master、与连接到宿主机的传感器(如网络摄像头)通信等,使用--net=host
可以极大简化网络配置,让容器内的 ROS 环境像直接在宿主机运行一样方便。示例:
1
2
3
4# 使用 host 网络模式运行容器
docker run -it --rm --net=host ubuntu:20.04 bash
# 在容器内运行 ifconfig,你会看到宿主机的网络接口
# 在容器内运行的 ROS 节点可以直接与宿主机或其他局域网内的 ROS 节点通信
-e
或--env
(环境变量)设置容器内的环境变量。格式:
-e KEY=VALUE
。为什么对 SLAM 重要?
- ROS 配置: 设置
ROS_MASTER_URI
,ROS_IP
,ROS_HOSTNAME
等。 - 显示转发 (X11 Forwarding): 让容器内的 GUI 程序(如 RViz, Gazebo, rqt_plot)能显示在宿主机的屏幕上。通常需要设置
DISPLAY
环境变量。
- ROS 配置: 设置
**示例 (X11 Forwarding):**注意: X11 Forwarding 配置有时比较棘手,可能因系统而异。
-net=host
通常能简化这个问题。1
2
3
4
5
6
7
8
9# 在宿主机先执行 xhost +local:docker (允许本地 docker 容器连接 X server)
xhost +local:docker
# 运行容器时传递 DISPLAY 环境变量,并挂载 X11 socket
docker run -it --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
--net=host \
ubuntu:20.04 bash
# 在容器内安装并运行一个简单的 GUI 程序试试,比如 xeyes (apt update && apt install -y x11-apps && xeyes)
--device
(挂载设备)将宿主机的设备文件挂载到容器内。
为什么对 SLAM 重要? SLAM 严重依赖传感器!你需要让容器访问连接到宿主机的摄像头、IMU、LiDAR 等设备。
**示例:**注意: 确保运行 Docker 的用户在宿主机上对这些设备文件有读写权限(通常需要将用户添加到
video
,dialout
等用户组)。1
2
3
4
5
6
7
8# 挂载第一个 USB 摄像头 (/dev/video0)
docker run -it --rm --device=/dev/video0 ubuntu:20.04 bash
# 挂载串口设备 (例如 IMU)
docker run -it --rm --device=/dev/ttyUSB0 ubuntu:20.04 bash
# 挂载多个设备
docker run -it --rm --device=/dev/video0 --device=/dev/ttyUSB0 ubuntu:20.04 bash
--gpus
(GPU 支持)- 允许容器访问宿主机的 NVIDIA GPU。这对需要 CUDA 加速的 SLAM 算法(如基于深度学习的特征提取、GPU 加速的优化)至关重要。
- 前提: 宿主机需要安装 NVIDIA 驱动和
nvidia-docker2
(或称为 NVIDIA Container Toolkit)。 - 示例:
1
2
3
4
5
6# 允许容器访问所有可用的 GPU
docker run -it --rm --gpus all nvidia/cuda:11.4.0-base-ubuntu20.04 nvidia-smi
# 上例使用了 NVIDIA 官方提供的包含 CUDA 的基础镜像,并运行 nvidia-smi 检查 GPU 是否可用
# 你也可以在你自己的 ubuntu:20.04 镜像基础上,在容器内安装 CUDA Toolkit,然后用 --gpus all 启动
docker run -it --rm --gpus all ubuntu:20.04 bash
# (进入容器后需要自行安装 CUDA 和相关驱动)
4. 查看容器 (docker ps)
- 作用: 列出正在运行的容器。
- 语法:
docker ps
- 查看所有容器 (包括已停止的):
- 语法:
docker ps -a
- 语法:
5. 进入正在运行的容器 (docker exec)
- 作用: 在一个已经在后台运行的容器内部执行命令。
- 语法:
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
- 常用选项:
-i
,-t
: 与docker run
中的含义相同,通常一起使用 (-it
) 来获取交互式 Shell。
- 示例:
进入我们之前后台运行的
my-nginx
容器,并启动一个 bash shell:执行后你将进入my-nginx
容器的 Shell。输入exit
退出该 Shell,但容器本身仍在后台运行。1
docker exec -it my-nginx bash
6. 管理容器 (停止、启动、删除)
- 停止容器:
- 语法:
docker stop <容器ID或名称>
- 示例:
docker stop my-nginx
- 语法:
- 启动已停止的容器:
- 语法:
docker start <容器ID或名称>
- 示例:
docker start my-nginx
(容器会继续在后台运行)
- 语法:
- 删除容器:
- 注意: 只能删除已停止的容器。
- 语法:
docker rm <容器ID或名称>
- 示例: (先停止)
docker stop my-nginx
(再删除)docker rm my-nginx
- 强制删除运行中的容器 (不推荐,除非你知道后果):
docker rm -f <容器ID或名称>
- 清理所有已停止的容器:
- 语法:
docker container prune
(会提示确认)
- 语法:
7. 删除镜像 (docker rmi)
- 作用: 删除本地的一个或多个镜像。
- 注意: 如果有容器 (即使是已停止的) 正在使用该镜像,需要先删除这些容器才能删除镜像。
- 语法:
docker rmi <镜像ID或仓库名:标签>
- 示例:
- 删除
hello-world
镜像:docker rmi hello-world:latest
- 删除
ubuntu:22.04
镜像 (如果之前没有基于它创建并保留的容器):docker rmi ubuntu:22.04
- 删除
- 清理悬空镜像 (dangling images): 这些是没有标签且没有被任何容器使用的镜像层,通常是构建过程中产生的中间层或旧版本。
- 语法:
docker image prune
- 语法:
我自己的实例
1. 需要用gpu的话先配置gpu
https://blog.csdn.net/GritYearner/article/details/133679403
1 | curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ |
2. 利用鱼香ros的镜像启动一个容器
1 | sudo docker run -dit \ |
这里注意不要直接使用鱼香的容器,他的默认的启动跟这个不太一样。启动时候的这些指令一旦运行,就不能再改了,最好是删除容器重新从镜像用正确指令生成一个容器,实在不想放弃这个容器的话就通过将这个容器生成为新的镜像,再从新镜像用正确指令生成容器
1 | docker commit 容器名 新镜像名:标签 |
要使用图形界面需要在外面终端运行
1 | # 这是鱼香ros默认运行的 |
3. 已经装好了ORB-SLAM3和ROS的镜像
我通过之前的鱼香镜像生成容器配置好orbslam3自己做了一个镜像上传到了dockerhub
1 | docker login |
sudo docker run
:sudo
: 以超级用户(root)权限执行后面的命令。运行 Docker 命令,特别是涉及硬件访问(如 GPU、设备挂载/dev
)或修改网络设置(--net=host
)时,通常需要sudo
权限。docker run
: 这是 Docker 的核心命令,用于根据指定的镜像创建一个新的容器并运行它。
-dit
: 这是三个选项的缩写合并:-d
(--detach
): 让容器在后台运行(Detached mode)。执行此命令后,你会立即返回到宿主机的终端提示符,而不是直接进入容器的 Shell。容器会在后台保持运行状态。这对于运行需要长时间提供服务的容器(如 ROS Master、模拟器)很有用。-i
(--interactive
): 保持标准输入(STDIN)对容器开放,即使没有连接到容器。这通常与-t
一起使用,以便后续可以通过docker attach
或docker exec
进行交互。-t
(--tty
): 为容器分配一个伪终端(pseudo-TTY)。这使得你后续通过docker exec
进入容器时,能获得一个类似真实终端的交互体验(例如,有命令提示符、支持 Tab 补全等)。- 组合效果:
-dit
启动一个后台运行的容器,但保持其交互接口可用,方便你之后使用docker exec -it rosslam bash
等命令进入容器内部进行操作。
--gpus all
:- 允许这个容器访问宿主机上所有可用的 NVIDIA GPU。
- 前提: 你的宿主机需要正确安装 NVIDIA 显卡驱动,并且安装了 NVIDIA Container Toolkit (nvidia-docker2)。
- 用途: 对于需要 CUDA 进行加速的 SLAM 算法(例如,基于深度学习的特征提取、GPU 加速的后端优化、仿真渲染等)至关重要。
-e NVIDIA_DRIVER_CAPABILITIES=all
:-e
(--env
): 设置容器内部的环境变量。NVIDIA_DRIVER_CAPABILITIES=all
: 这个特定的环境变量告诉 NVIDIA 驱动程序,允许容器使用驱动程序的所有功能(如图形、计算、工具、视频编解码等)。通常与--gpus
选项配合使用,以确保容器内应用能充分利用 GPU 能力。
--name=rosslam
:- 给这个新创建的容器指定一个名字,叫做 “rosslam”。
- 好处: 你可以使用这个名字来方便地管理容器,例如
docker stop rosslam
、docker start rosslam
、docker logs rosslam
、docker exec -it rosslam bash
等,而不需要记住 Docker 自动生成的长 ID。
--privileged
:- 赋予这个容器扩展的权限。这基本上禁用了容器和宿主机之间的大部分安全隔离机制。
- 效果: 容器几乎拥有与宿主机上 root 用户相同的权限,可以访问宿主机的所有设备(
/dev
下的所有内容),修改内核参数等。 - 使用场景: 通常是为了确保容器能够无障碍地访问各种硬件设备(摄像头、IMU、LiDAR 等),尤其是在
-v /dev:/dev
挂载了整个设备目录的情况下,确保权限足够。 - 注意: 这是一个强大的选项,但有安全风险。如果可能,优先考虑使用更精细的
--device
选项来只挂载必要的设备,而不是使用--privileged
。但有时为了方便或解决特定权限问题会使用它。
-v /dev:/dev
:-v
(--volume
): 将宿主机的目录或文件挂载到容器内部。这里是挂载宿主机的/dev
目录到容器的/dev
目录。- 目的: 让容器可以直接访问宿主机上的所有硬件设备文件。这对于 SLAM 来说非常方便,因为你可以直接在容器内像在宿主机上一样使用
/dev/video0
(摄像头)、/dev/ttyUSB0
(串口设备如 IMU 或 LiDAR)等设备。 - 与
--privileged
的关系: 这个挂载让容器 看到 设备文件,而--privileged
通常用来确保容器 有权限 去操作这些设备文件。
-v /home/xfy/docker-ros:/home/rosslam/workspace
:- 这是另一个卷挂载。
宿主机路径
:/home/xfy/docker-ros
(这是你宿主机上的一个具体目录,其他人使用时需要修改成他们自己的路径!)容器内路径
:/home/rosslam/workspace
- 目的: 这是实现代码和数据共享的关键。你在宿主机的
/home/xfy/docker-ros
目录下修改代码、存放数据,这些内容会实时同步到容器内的/home/rosslam/workspace
目录,反之亦然。这样你可以在宿主机使用你喜欢的编辑器,而在容器内编译和运行。容器删除后,这个目录下的工作成果依然保存在宿主机上。
-v /tmp/.X11-unix:/tmp/.X11-unix
:- 挂载宿主机的 X11 Unix Domain Socket 目录到容器内部对应的位置。
- 目的: 这是实现 X11 转发(让容器内的 GUI 程序显示在宿主机屏幕上)的关键步骤之一。GUI 程序通过这个 Socket 与宿主机的 X Server 通信。
-e DISPLAY=unix$DISPLAY
:- 设置容器内的
DISPLAY
环境变量。 $DISPLAY
: 这会取用你当前宿主机的DISPLAY
环境变量的值(通常是:0
或:1
等)。unix
: 有时会加上这个前缀,但很多时候直接-e DISPLAY=$DISPLAY
也能工作。- 目的: 告诉容器内的 GUI 应用程序应该将图形界面发送到哪个显示服务器(即你的宿主机屏幕)。需要与上一步的 X11 Socket 挂载配合使用。
- 前提: 在运行这个
docker run
命令之前,你可能需要在宿主机上执行xhost +local:docker
(或者更安全的特定容器授权命令)来允许来自 Docker 容器的 X11 连接。
- 设置容器内的
-w /home/rosslam
:-w
(--workdir
): 指定容器启动后的默认工作目录。- 效果: 当你使用
docker exec -it rosslam bash
进入容器时,你的 Shell 会话将直接从容器内的/home/rosslam
目录开始,而不是默认的根目录/
。这通常是为了方便,让你直接进入项目相关的主目录。
--net=host
:- 让容器共享宿主机的网络命名空间(Network Namespace)。
- 效果: 容器不会获得自己独立的 IP 地址,而是直接使用宿主机的网络接口和 IP 地址。容器内监听的端口会直接暴露在宿主机的对应端口上,无需使用
-p
进行端口映射。 - 对 ROS/SLAM 的好处: 极大地简化了网络配置。容器内的 ROS 节点可以像在宿主机上运行一样,轻松地被局域网内(包括宿主机)的其他 ROS 节点发现和通信(例如 RViz 连接容器内的 ROS Master)。也方便访问连接到宿主机的网络摄像头等设备。
- 缺点: 降低了网络隔离性。
xuefeiyang/fyslam:slam3WithRos
:- 这是用来创建容器的镜像(Image)。
xuefeiyang/fyslam
: 镜像的仓库名/用户名和镜像名,这看起来是一个用户(xuefeiyang)构建并可能分享在 Docker Hub 或私有仓库的自定义镜像。slam3WithRos
: 镜像的标签(Tag),通常表示镜像的版本或者配置。这个名字暗示了这个镜像里面很可能已经预装了 ROS (Robot Operating System) 和一些 SLAM 相关的库或工具。
总结
这个命令启动了一个名为 rosslam
的后台容器,该容器基于 xuefeiyang/fyslam:slam3WithRos
镜像。它被赋予了很高的权限 (--privileged
),可以直接访问宿主机的所有 GPU (--gpus all
) 和所有设备 (-v /dev:/dev
),并且共享宿主机的网络 (--net=host
)。它还设置了 GUI 转发 (-v /tmp/.X11-unix
, -e DISPLAY
),并将宿主机的 /home/xfy/docker-ros
目录映射到容器的 /home/rosslam/workspace
以共享工作文件。容器启动后的默认工作目录是 /home/rosslam
。