文章目录
Docker一个能够实现跨平台运行程序实例的工具,其底层原理基于linux container的接口实现,是一个轻量级的虚拟化技术,类似于多系统的孵化机制,但是与虚拟机相比,它不需要完整的操作系统,而是共享宿主机的操作系统内核,因此容器启动更快、占用资源更少。通过 Docker,开发者可以确保在不同的环境中运行应用时,不会出现因环境不一致而导致的问题。
Docker 的核心概念包括 镜像
和 容器
。镜像是一个包含应用及其依赖的只读模板,可以对应理解它为编译好的可执行文件,而容器是从镜像创建的可执行实例,可以理解它为程序(分别有运行,挂起,停止等等状态)。
docker_4">docker安装及使用
docker_5">安装 docker
- 更新系统软件包列表
sudo apt update
- 安装必要的依赖包
sudo apt install apt-transport-https ca-certificates curl software-properties-common
- 添加 Docker 的官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
如果报以下错误:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to download.docker.com:443
gpg: 找不到有效的 OpenPGP 数据。
换成国内镜像源,如阿里:
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
- 添加 Docker 软件源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- 更新软件包列表以包含 Docker 软件源
sudo apt update
- 安装 Docker 引擎
sudo apt install docker-ce docker-ce-cli containerd.io
- 将当前用户添加到
docker
用户组,避免每次使用 Docker 都需要输入sudo
一下二选一
-
1.查看docker用户组是否存在
sudo cat /etc/group | grep docker
没有可以添加docker组
sudo groupadd docker
添加用户到docker组
sudo gpasswd -a ${USER} docker
-
2.添加当前用户到docker组
sudo usermod -aG docker $USER
需要注销并重新登录,使设置生效。注销不生效就重启
docker__64">docker 常用命令
docker__65">docker 基本命令
-
查看 docker 版本
获取当前安装的 docker 版本。docker --version
输出类似:
Docker version 20.10.8, build 3967b7d
-
查看 Docker 系统信息
显示有关 Docker 配置、系统资源、镜像、容器等的详细信息。docker info
容器
-
容器创建
docker run
命令的主要功能是基于指定的镜像创建一个新的容器,并启动该容器。它是一个组合操作,涵盖了容器的创建和启动两个步骤。#eg: 创建并启动容器,同步映射共享文件,注意-v要在bash前 docker run -it -v ~/docker_ws/ros2_ws:/home/ros2_ws -it --name ros2 --net=host ros:humble-ros-base bash
-
容器启动
docker start
命令的作用是启动一个已经存在但处于停止状态的容器。它不会创建新的容器,只是将之前停止的容器重新启动,恢复到运行状态,常与-a
(--attach
),用于在启动容器后附加到容器的标准输出和标准错误输出,即显示容器登录界面,但是不启动交互。#eg: docker start -a my_containe
-
停止容器
docker stop <容器ID或名称>
-
重启容器
docker restart <容器ID或名称>
-
在运行的容器中执行命令
docker exec
命令用于在运行的容器中执行命令,可以通过它在容器内交互式或后台运行命令。
通常用于重新进入容器并打开一个新的终端会话。该命令适用于需要在容器中同时进行多个操作的场景。docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
-
进入容器的交互式 Shell:
进入容器并获得一个交互式 shell,可以使用以下命令:docker exec -it <容器名称或ID> bash
这会在容器内启动一个交互式的 Bash shell。
-
后台执行命令:
在后台运行命令,可以使用-d
参数:docker exec -d <容器名称或ID> <命令> #eg: docker exec -d <容器名称或ID> ls /tmp
-
在容器中运行简单的命令:
你可以直接在容器中执行一个命令,而不进入交互式 shell:docker exec <容器名称或ID> ls /路径/到/目录
-
运行带有环境变量的命令:
如果你需要在容器内运行一个命令并指定环境变量,可以使用-e
参数:docker exec -e VAR_NAME=value <容器名称或ID> <命令>
-
进入已经退出且停止的容器
# 启动容器 docker start <容器 ID 或容器名称> # 进入容器 docker exec -it <容器 ID 或容器名称> /bin/bash #eg: docker start my_container docker exec -it my_container /bin/bash
-
连接到正在运行的容器的主进程
docker attach
命令用于连接到正在运行的容器的主进程(通常是启动容器时执行的第一个命令),回到之前退出的会话。docker attach <容器 ID 或容器名称> #eg: docker attach my_container
-
exec
与attach
docker exec
在运行中的容器内启动新的进程,并分配独立的终端(如 /bin/bash)
用途:在容器内执行独立命令(如调试、修改配置、查看进程)
docker attach
直接连接到容器主进程的标准输入/输出流(即原始终端),不启动新进程
用途:实时查看容器主进程的输出(如日志流) -
列出正在运行的容器
docker container ls docker ps
-
列出所有容器(包括已停止的)
docker container ls -a docker ps -a
-
删除容器
docker rm <容器ID或名称> #-f 强制删除: docker rm -f <容器ID或名称>
-
重新进入容器
如果后续还需要使用该容器,可以使用以下命令重新启动并进入:docker start ros2_container docker attach ros2_container
-
docker logs -f <容器ID或名称>
-
删除所有停止的容器
删除所有停止的容器,可以帮助清理不再使用的容器。docker container prune
-
docker inspect <容器ID或名称>
镜像
-
列出images(镜像)
docker images
-
**拉取镜像
从 Docker Hub 或其他注册中心拉取镜像。docker pull <镜像名称>:<标签> #eg: docker pull ubuntu:latest
-
删除镜像
删除指定镜像。注意:如果镜像被容器使用,删除镜像时会提示错误。docker rmi <镜像ID或镜像名>:<标签> #eg: docker rmi ubuntu:latest #-f 强制删除: docker rmi -f <镜像ID或名称>
-
构建镜像
使用 Dockerfile 文件构建镜像,<路径> 是包含 Dockerfile 的目录。docker build -t <镜像名称>:<标签> <路径> #eg: docker build -t myapp:v1 .
-
提交镜像
提交容器为新镜像(镜像指的是image,为容器基板,容器指的是基于image构建的修改的可启动的镜像)docker commit <容器ID或名称> 新镜像名称:标签
-
**推送镜像到远程仓库
将本地镜像推送到 Docker Hub 或其他 Docker 注册仓库。docker push <镜像名称>:<标签> #eg: docker push myapp:v1
卷
-
docker与宿主机文件共享/路径挂载
在 Docker 中,-v
、--mount
和--volumes-from
都与容器的卷挂载相关。-
-v
是传统的挂载方式,语法简洁,适合简单的挂载场景。 -
--mount
语法更详细、灵活,支持多种挂载类型,推荐用于复杂的挂载需求。 -
--volumes-from
用于在多个容器间共享卷挂载配置,减少重复操作。-v
选项 -
功能:用于在创建容器时将宿主机的目录或文件系统中的一个卷挂载到容器内的指定路径。当使用宿主机路径时,它会直接将宿主机上的指定目录或文件挂载到容器内;若使用卷名,会先检查该卷是否存在,不存在则会自动创建一个新的匿名卷。
-
选项说明:常见的选项有
ro
(只读挂载),例如-v /host/path:/container/path:ro
表示将宿主机路径以只读方式挂载到容器内。 -
示例:
- 挂载宿主机目录:
docker run -it -v /home/user/host_data:/container_data ubuntu
- 使用命名卷:
docker volume create my_volume docker run -it -v my_volume:/container_data ubuntu
-
特点:语法简洁,是一种较为传统的挂载方式,但在一些复杂的挂载需求上,表达能力相对较弱。
--mount
选项- 语法:
--mount type=挂载类型,source=源,target=目标,选项
- 功能:
--mount
是一种更详细、更灵活的挂载方式,支持多种挂载类型,如bind
(挂载宿主机目录)、volume
(使用 Docker 卷)、tmpfs
(临时文件系统)等。 - 示例:
- 挂载宿主机目录:
docker run -it --mount type=bind,source=/home/user/host_data,target=/container_data ubuntu
- 使用 Docker 卷:
docker volume create my_volume docker run -it --mount type=volume,source=my_volume,target=/container_data ubuntu
- 挂载临时文件系统:
docker run -it --mount type=tmpfs,target=/container_tmpfs ubuntu
- 特点:语法更加明确和详细,每个参数的作用清晰,便于理解和维护,推荐在复杂挂载场景中使用。
--volumes-from
选项- 语法:
--volumes-from 容器名或容器 ID
- 功能:该选项用于从一个已经存在的容器中复制其所有的卷挂载配置到新创建的容器中。新容器会共享原容器挂载的所有卷,包括卷的读写权限等配置。
- 示例:
# 先创建一个挂载了卷的容器 docker run -it -v /home/user/host_data:/container_data --name source_container ubuntu # 创建一个新容器并共享 source_container 的卷 docker run -it --volumes-from source_container --name new_container ubuntu
- 特点:主要用于在多个容器之间共享相同的卷挂载配置,避免重复配置卷挂载,提高效率。
-
-
查看路径挂载情况
docker inspect <容器ID或名称> | grep Mounts
-
多文件路径挂载
docker run -d \ --name <新容器名称> \ -v /原宿主机路径:/原容器路径 \ -v /新宿主机路径:/新容器路径 \ 新镜像名称:标签 #eg: docker run -it -v /opt/ros/melodic:/opt/ros/melodic -v /home/workspace/docker_ws/ros2_ws:/home/ws/ros2_ws -it --name ros2 --net=host ros2:ros1-bridge bash
也可以通过修改docker配置文件:
/var/lib/docker/containers/<容器ID>/config.v2.json
(注意一定要先关闭容器,此外该方法容易使得容器崩溃)
MountPoints
字段中修改以下内容:"/新容器路径": { "Source": "/宿主机路径", "Destination": "/新容器路径", "RW": true, "Type": "bind" }
-
列出 Docker 卷
列出当前的 Docker 数据卷。docker volume ls
-
创建 Docker 卷
创建一个新的数据卷,用于持久化数据。docker volume create <卷名称>
-
删除 Docker 卷
删除一个或多个不再使用的卷。docker volume rm <卷名称>
-
删除所有未使用的卷
删除所有未被容器使用的卷。docker volume prune
网络命令
-
查看 Docker 网络
查看当前 Docker 环境中的所有网络。docker network ls
-
创建 Docker 网络
创建一个新的自定义网络。docker network create <网络名称>
-
docker network connect <网络名称> <容器ID或名称>
-
docker network disconnect <网络名称> <容器ID或名称>
Docker Compose
Docker Compose 允许你定义和运行多个容器应用。通常,它通过 docker-compose.yml
文件定义服务。
-
启动所有服务
根据docker-compose.yml
文件启动所有服务。docker-compose up
-
后台启动服务
在后台启动服务(使用-d
参数)。docker-compose up -d
-
停止服务
停止所有由docker-compose.yml
启动的服务。docker-compose down
-
查看日志
查看通过 Docker Compose 启动的服务的日志。docker-compose logs
-
重新构建服务
如果需要重新构建镜像,可以使用以下命令。docker-compose build
-
列出 Docker Compose 服务
列出当前 Docker Compose 项目中启动的容器。docker-compose ps
Docker 系统命令
-
清理无用的资源
删除无用的容器、镜像、网络和卷,以释放磁盘空间。docker system prune
-
查看 Docker 容器和镜像的大小
查看 Docker 容器、镜像和数据卷的占用空间。docker system df
dockerROS2_humble_465">在docker中安装ROS2 humble
以下是在Docker上安装ROS 2 并接收外部 ROS 2 话题(topic)数据的详细步骤:
拉取 ROS 2 Docker 镜像
这里以 ROS 2 Humble 版本为例,你可以根据需求选择其他版本。
docker pull ros:humble-ros-base
pull timeout
的问题,使用下述方法更新镜像源
- 打开
daemon.json
文件,以下用vim
打开
sudo vim /etc/docker/daemon.json
- 在文件内添加如下内容,保存退出
{"max-concurrent-downloads": 10,"max-concurrent-uploads": 5,"default-shm-size": "1G","debug": true,"experimental": false,"registry-mirrors":["https://x9r52uz5.mirror.aliyuncs.com","https://dockerhub.icu","https://docker.chenby.cn","https://docker.1panel.live","https://docker.awsl9527.cn","https://docker.anyhub.us.kg","https://dhub.kubesre.xyz"]
}
- 重启docker
sudo systemctl restart docker
运行 ROS 2 Docker 容器
- **运行容器并进入交互式终端
docker run -it --name ros2_container --net=host ros:humble-ros-base bash
配置 ROS 2 环境
在容器内执行以下命令来配置 ROS 2 环境:
source /opt/ros/humble/setup.bash
接收外部 ROS 2 话题
-
**确认外部 ROS 2 节点正常运行并发布话题
确保外部的 ROS 2 节点已经启动,并且正在发布你想要接收的话题。 -
**列出可用的话题
在容器内运行以下命令列出所有可用的话题:
ros2 topic list
如果能看到你想要接收的话题,说明网络通信正常。
- **订阅并接收话题数据
假设要接收的话题名称为topic
,使用以下命令订阅该话题并打印其数据:
ros2 topic echo topic
这样,你就可以在终端中看到 topic
话题发布的消息内容了。
注意事项
- 确保主机和外部 ROS 2 节点在同一网络中,并且网络配置允许它们相互通信。
- 如果遇到权限问题或网络问题,可以检查 Docker 容器的权限设置和网络配置。
下面的介绍存在问题,ros1_bridge编译问题。仅供参考。
docker_ros2_558">ros1 和docker ros2通信
在Docker中安装的ROS2是否能够接收宿主机上ROS1的消息,理论上是可以的,但需要使用一些特殊的工具和设置,因为ROS1和ROS2之间并不直接兼容。为了解决这个问题,ROS提供了一个名为**ros1_bridge
**的工具,它可以在ROS1和ROS2之间实现消息的转换和桥接。
使用 ros1_bridge
桥接 ROS1 和 ROS2
ros1_bridge
是 ROS 提供的一个桥接工具,它可以让你在 ROS1 和 ROS2 之间传递消息。通过这个桥接,ROS2中的节点可以接收到ROS1发布的消息,反之亦然。
步骤概述
-
确保宿主机上运行的是ROS1和ROS2:
需要在宿主机上安装并配置好ROS1和ROS2。ROS1和ROS2需要在宿主机中各自独立运行。确保它们可以正常通信。 -
在Docker中安装ROS2:
你需要确保Docker容器中已经正确安装并配置了ROS2。可以使用官方的ROS2 Docker镜像,或者自己构建一个镜像。 -
构建和运行
ros1_bridge
:
在Docker容器中,你需要构建并启动ros1_bridge
来桥接ROS1和ROS2的消息。 -
配置 ROS1 和 ROS2 环境:
在ROS1和ROS2的环境中,ROS1发布的消息需要通过ros1_bridge
转发到ROS2。
详细步骤
- **1. 安装并启动 ROS1 和 ROS2
假设你已经在宿主机上安装了ROS1和ROS2。你可以分别使用以下命令启动它们:
-
启动 ROS1 (假设使用
melodic
版本):source /opt/ros/melodic/setup.bash roscore
-
启动 ROS2 (假设使用
foxy
版本):source /opt/ros/foxy/setup.bash ros2 daemon start
-
**2. 安装并配置
ros1_bridge
在Docker容器中,你需要安装ros1_bridge
来桥接ROS1和ROS2。你可以按照以下步骤进行操作:
-
安装 ROS1 和 ROS2(如果你还没有安装):
- ROS1(例如Melodic)和ROS2(例如Foxy)安装:
- 在Dockerfile中添加安装命令,或直接在Docker容器中使用APT进行安装。
apt-get update apt-get install ros-<ros1-distro>-ros-base apt-get install ros-<ros2-distro>-ros-base
- ROS1(例如Melodic)和ROS2(例如Foxy)安装:
-
安装
ros1_bridge
:
你需要构建并安装ros1_bridge
,这是一个在ROS1和ROS2之间转发消息的包。为了确保成功构建,ros1_bridge
需要你已经安装了ROS1和ROS2。-
进入ROS2工作空间:
mkdir -p ~/ros2_ws/src cd ~/ros2_ws/src
-
克隆
ros1_bridge
:git clone https://github.com/ros2/ros1_bridge.git
-
安装依赖并编译:
cd ~/ros2_ws rosdep install --from-paths src --ignore-src -r -y colcon build --packages-select ros1_bridge --cmake-force-configure
-
-
**3. 运行
ros1_bridge
并启动桥接 -
在 Docker 容器内启动 ROS1 和 ROS2 桥接器:
#ros1source /opt/ros/melodic/setup.bash # ROS1环境roscore
#ros2ros2 run ros1_bridge dynamic_bridgesource /opt/ros/foxy/setup.bash # ROS2环境
ros1_bridge
会自动检测当前ROS1和ROS2中可以桥接的消息类型,并启动相应的桥接连接。
以下命令可以查看当前 ros1_bridge
支持的消息类型对:
ros2 run ros1_bridge dynamic_bridge --print-pairs
作用
-
显示支持的消息对:该命令会列出当前在 ROS 1 和 ROS 2 之间能够桥接的消息类型对。例如,ROS 1 中的
std_msgs/String
类型和 ROS 2 中的std_msgs/msg/String
类型的桥接会出现在输出列表中。 -
诊断桥接问题:如果你遇到无法桥接某些消息类型的问题,可以运行
--print-pairs
来查看是否有已知的桥接支持。如果消息对没有列出,可能意味着ros1_bridge
不支持这些类型的桥接,或者你需要手动添加支持。
自动桥接所有支持的消息类型
ros2 run ros1_bridge dynamic_bridge --bridge-all-topic
-
**4. 配置消息发布和订阅
-
在ROS1节点中发布消息:
rostopic pub /chatter std_msgs/String "data: 'Hello from ROS1'"
-
在ROS2节点中订阅ROS1消息:
ros2 topic echo /chatter
通过ros1_bridge
,你应该能够在Docker容器内运行的ROS2节点接收宿主机上ROS1发布的消息。
注意事项
-
ROS版本兼容性:确保使用的ROS1和ROS2版本之间的兼容性。例如,ROS2 Foxy与ROS1 Melodic通常是兼容的,但如果版本不匹配,可能需要其他解决方法。
-
性能和延迟:
ros1_bridge
引入了一定的延迟,因此在高性能要求的系统中使用时,可能需要特别注意。
通过这些步骤,你应该能够在Docker容器中的ROS2节点接收到宿主机上ROS1的消息。