ROS-Docker在容器中运行ROS

ROS-Docker在容器中运行ROS

Louis 655 2020-01-29

新年假期在家里无事,把弄了一下Docker这个东西,于是有了这一篇笔记。分类是技术总结,所以过来看聊骚的就可以直接关闭了。

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

CentOS下部署Docker环境

本节会在CentOS下安装Docker,完成后,系统可以运行docker的相关命令。

  • 运行环境:CentOS 7
  • 内核版本:3.10.0-1062.9.1.el7.x86_64
sudo yum install docker-io
sudo service docker start

一些常用的docker命令

sudo service docker stop # 用于关闭Docker服务
docker ps # 用于查看正在运行的容器
docker images # 用于查看本地的镜像
docker stop 容器id #关闭容器
docker kill 容器id #强制关闭容器
docker start 容器id #开启容器
docker restart 容器id #重启容器
docker rm 容器id #删除已经停止的容器
docker rm -f 容器id #强制删除容器

制作Docker镜像

本节会利用Dockerfile制作自己的镜像。其后的内容会利用这个镜像进行。
目录结构如下:

.
└── ros_docker
    └── Dockerfile
cd ros_docker
vi Dockerfile

编写Dockerfile

FROM ros:kinetic

CMD ["roscore"]

EXPOSE 11311

这个docker开启的时只打开一个rosmaster并不做其他事情

使用如下命令构建和运行自建的Docker

docker build -t my-ros-app .
docker images # 可以看到自己做的镜像
docker run -it --rm --name my-runnning-app my-ros-app

Docker镜像上传到阿里云镜像仓库

制作的Docker如果保存在本地,可能在服务器重新部署的时候丢失,最好把它推送到某个镜像仓库,可以作更好的保存以及被其他主机下载

这部分可以登陆阿里云。在创建镜像仓库的时候会有相关的操作指南。

  1. 注册一个阿里云账号
  2. 开启容器镜像服务
  3. 建立一个命名空间
  4. 建立一个镜像仓库
  5. 往镜像仓库中推送上传镜像
docker login --username=账号 registry.cn-shenzhen.aliyuncs.com
# 这一步会提示输入密码
sudo docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/kungfu-robotics/kfr_ros_base:[镜像版本号]
docker push [name]
sudo docker push registry.cn-shenzhen.aliyuncs.com/[命名空间]/[镜像名]:[镜像版本号]
# 这一步会经历漫长的上传过程,随后就可以在阿里云看到了
# Docker采用分层架构,每次更新只上传增量的部分,只是第一步的上传会花点时间 后面需要上传的东西不多

容器维护

本节中有一些指令用于进入容器进行一些修改,还可以把修改的内容提交到镜像当中。

使用exec指令进入容器

docker exec --help # 查看命令用法

Usage:	docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Run a command in a running container

Options:
  -d, --detach               Detached mode: run command in the background
      --detach-keys string   Override the key sequence for detaching a container
  -e, --env list             Set environment variables (default [])
      --help                 Print usage
  -i, --interactive          Keep STDIN open even if not attached
      --privileged           Give extended privileges to the command
  -t, --tty                  Allocate a pseudo-TTY
  -u, --user string          Username or UID (format: <name|uid>[:<group|gid>])

docker ps # 查看正在运行的容器
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2f33c961e90f        d63439629c2e        "/ros_entrypoint.s..."   17 minutes ago      Up 16 minutes                           pedantic_mccarthy
docker exec -it pedantic_mccarthy bash #使用bash终端进入容器

提交对容器的修改

# docker commit -m="提交的附加信息" --author="作者名" 容器id 镜像id
$ docker commit -m "commit test" --author "louis" 2f33c961e90f d63439629c2e
sha256:3cb612f73dbdb7a91b3eed6beba3e6d27b1fc8cb78b69eb56609a6460ce04951
# 使用上一步推送镜像的方式推送进行更新

ROS-Docker

ROS的此dockerized映像旨在为构建和部署分布式机器人应用程序提供简化且一致的平台。它由Ubuntu官方映像和ROS的Debian官方软件包构建而成,包括最近支持的发行版本,可用于快速访问和下载。这为研究和工业领域的机器人技术人员提供了一种简便的方法来开发,重用和运输用于自主动作和任务计划,控制动态,本地化和绘图,群体行为以及常规系统集成的软件。

用最新发布的算法的先进实现来开发这样的复杂系统仍然具有挑战性,因为机器人软件的可重复性和可重复性可能会落入创新之路。随着编码,调整和部署跨越许多工程学科的多个软件组件的难度增加,一种更具协作性的方法变得有吸引力。但是,在多个机器人和平台上共享和维护软件集合的技术难题,一段时间以来已经超出了许多小型实验室和企业所能承受的时间和精力。

随着软件容器的进步和标准化,机器人专家已准备好购买大量改进的开发人员工具以构建和运输软件。为了缓解采用新方法带来的烦恼和技术挑战,我们致力于提供官方资源,以将ROS与这些新技术一起使用。

建立镜像

编写Dockerfile:如下:

FROM ros:kinetic

RUN apt-get update && apt-get install -y \
    ros-kinetic-ros-tutorials \
    ros-kinetic-common-tutorials \
    && rm -rf /var/lib/apt/lists/

Dockerfile中对apt进行update,而后安装了下面会用到的listener和talker节点。

在统一目录下构建镜像

$ docker build --tag ros:ros-tutorials .
# 在当前目录下构建tag为ros:ros-tutorials的docker镜像,随后可以使用docker images 找到构建的镜像

建立网络

需要建立一个新的网络foo,使用network指令:

docker network create foo

现在我们有了网络,我们可以创建服务。服务在网络上在此发布位置,从而轻松解析服务特定容器的位置/地址。我们将使用此方法确保ROS节点可以找到并连接到ROS master。

运行服务

运行一个rosmaster

docker run -it --rm \
    --net foo \ # 连接到foo网络
    --name master \ #运行后容器命名为master
    ros:ros-tutorials \ #运行tag为ros-tutorials的镜像
    roscore # 容器启动后运行master

随后会看见master正在运行。接下来添加talker节点,需要把talker节点的环境变量指向主服务

在另一个终端运行指令:

docker run -it --rm \
    --net foo \ # 连接到foo网络
    --name talker \ #运行后容器命名为talker
    --env ROS_HOSTNAME=talker \ 
    --env ROS_MASTER_URI=http://master:11311 \ #连接到master所在容器
    ros:ros-tutorials \ #运行tag为ros-tutorials的镜像
    rosrun roscpp_tutorials talker # 容器启动后运行talker

可以看见talker节点在运行。然后在另一个终端中,listener类似地运行该节点:

docker run -it --rm \
    --net foo \
    --name listener \
    --env ROS_HOSTNAME=listener \
    --env ROS_MASTER_URI=http://master:11311 \
    ros:ros-tutorials \
    rosrun roscpp_tutorials listener

好的!您应该看到listener现在正在回显每个消息的talker广播。然后,您可以列出容器并看到类似以下内容的内容:

$ docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
67ce73355e67        listener            foo                 a62019123321
917ee622d295        master              foo                 f6ab9155fdbe
7f5a4748fb8d        talker              foo                 e0da2ee7570a

也可以列出所有的容器:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS              PORTS               NAMES
a62019123321        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           listener
e0da2ee7570a        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute   11311/tcp           talker
f6ab9155fdbe        ros:ros-tutorials   "/ros_entrypoint.sh    About a minute ago   Up About a minute

可以用上文提到的维护容器的方式进入某个容器中监听topic或者查看节点的运行情况。这里不在赘述。

关闭容器

要停止已经开启的容器,我们只需要停止容器和服务即可。我们可以使用Ctrl^C启动容器的位置或使用带有我们为其命名的名称的stop命令来停止和删除容器:

$ docker stop master talker listener
$ docker rm master talker listener

使用Docker Compose运行多容器程序

Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,您可以使用YAML文件来配置应用程序的服务。然后,使用一个命令,就可以从配置中创建并启动所有服务。

使用Compose基本上是一个三步过程:

  1. 使用定义您的应用环境,Dockerfile以便可以在任何地方复制。
  2. 定义组成应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。
  3. 运行docker-compose upand Compose启动并运行您的整个应用程序。

新建docker-compose.yml

建立一个rostutorials文件夹,将上文中建立的Dockerfile移动到该目录中。然后docker-compose.yml在同一个目录中创建一个名为yaml的文件,并将以下内容粘贴到其中:

version: '2'
services:
  master:
    build: .
    container_name: master
    command:
      - roscore

  talker:
    build: .
    container_name: talker
    environment:
      - "ROS_HOSTNAME=talker"
      - "ROS_MASTER_URI=http://master:11311"
    command: rosrun roscpp_tutorials talker

  listener:
    build: .
    container_name: listener
    environment:
      - "ROS_HOSTNAME=listener"
      - "ROS_MASTER_URI=http://master:11311"
    command: rosrun roscpp_tutorials listener

docker-compose中包含了构建和运行三个docker容器,以及配置它们之间的网络关系。

执行docker-compose

在该目录下运行:

$ docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.

Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.

To deploy your application across the swarm, use `docker stack deploy`.

Creating network "rostutorials_default" with the default driver
Creating master ... 
Creating listener ... 
Creating talker ... 
Creating listener
Creating master
Creating master ... done

若出现提示:docker-compose命令不存在,修复方式参考:
docker-compose命令不存在、docker-compose not found

可以看见三个docker已经被脚本启动。也可以使用docker ps查看正在运行的容器,进行验证:

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES
b3fd2c69d8e0        rostutorials_master     "/ros_entrypoint.s..."   46 seconds ago      Up 44 seconds                           master
95fc183ac1e3        rostutorials_listener   "/ros_entrypoint.s..."   46 seconds ago      Up 44 seconds                           listener
9cfa258c9958        rostutorials_talker     "/ros_entrypoint.s..."   46 seconds ago      Up 44 seconds                           talker

注意,rostutorials_default现在已经创建了一个名为的新网络,您可以使用以下方法进一步检查它:

$ docker network inspect rostutorials_default

我们可以监视每个服务的记录输出,例如侦听器节点,如下所示:

$ docker-compose logs listener

最后,我们可以使用docker-copose从同一目录中停止并删除所有相关容器:

$ docker-compose stop
$ docker-compose rm

注意:自动生成的网络rostutorials_default将在Docker引擎的整个生命周期内持续存在,或者直到您使用明确将其删除为止

docker network rm rostutorials_default

参考网址

dockerhub中的ros介绍
dockerhub中的Docker Compose介绍