文章目录
- Docker 仓库管理
- docker连接远程仓库
- 容器命令
- 运行模式
- attached模式
- detached模式
- detached模式转换为attached模式
- 交互模式
- 文件复制
- 镜像导入导出
- 导出
- 镜像导出
- 容器导出
- commit 镜像
- 导入
- 停用全部运行中的容器
- docker删除所有容器
- 停用并删除容器
- 使用数据卷
- 匿名挂载和具名挂载
- 配置环境
- 查看容器信息
- runtime
- docker内存限额:
- CPU限制:
- DockerFile
- 常用命令
- 构建ROS镜像实例
- Dockerfile 构建镜像
- 查看镜像是如何通过DockerFile构建的
- Docker网络
- docker-compose
- 实例
- docker-compose启用GPU访问
- 旧版
- 新版
- 进阶问题
- docker 显示
- 为什么需要DRI
- Docker使用GPU
- 手动配置镜像
- 它是如何工作的?
- 权限问题
- No protocol specified问题
- 把用户添加进Docker用户组
Docker 仓库管理
docker连接远程仓库
$ docker login [OPTIONS] [SERVER]# docker login -u Username -p Password [SERVER]
Options:
- -p, --password string Password
–password-stdin Take the password from stdin - -u, --username string Username
- [SERVER]是服务器地址
容器命令
$ docker container run 参数 镜像名称:tag 执行的命令
参数
-p
:端口映射,第一个port
是本机的端口,第二个port
是Docker容器的端口-i
:保持和docker 容器内的交互,启动容器时,运行的命令结束后,容器依然存活,没有退出(默认是会退出,即停止的)-t
:为容器的标准输入虚拟一个tty-d
:后台运行容器--name string
:给容器起一个自定义名称--rm
:容器在启动后,执行完成命令或程序后就销毁
运行模式
attached模式
前台运行
detached模式
后台运行
开启方法:参数-d
或者--detach
detached模式转换为attached模式
docker attach
交互模式
直接进入交互模式
docker exec -it sh
文件复制
docker cp 容器ID:容器内文件路径 目的主机路径
镜像导入导出
导出
镜像导出
$ docker save [OPTIONS] IMAGE [IMAGE...]# docker save -o image.tar my/image
OPTIONS说明:
-o
:输出到文件
容器导出
$ docker export CONTAINER >name.tar
将容器以tar包的形式导出到标准输出,然后重定向到目标文件name.tar
commit 镜像
将容器转化为镜像
# 提交容器作为一个新的副本,命令与git类似docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]#eg: docker commit -m="提交的信息" -a="作者" 容器Id 目标镜像名:[Tag]
Options:
- -a, --author string Author (e.g., “John Hannibal Smith”)
- -c, --change list Apply Dockerfile instruction to the created image
- -m, --message string Commit message
- -p, --pause Pause container during commit (default true)
CONTAINER为容器ID或名字
[REPOSITORY[:TAG]]为镜像
导入
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
导入一个本地的tar包作为镜像
$ docker load [OPTIONS]# docker load < image.tar
OPTIONS说明:
- –input,-i:指定导入的文件,带起STDIN
- –quiet,-q:精简输出信息
停用全部运行中的容器
$ docker stop $(docker ps -q)
docker删除所有容器
$ docker rm $(docker ps -aq)
停用并删除容器
$ docker stop $(docker ps -q) && docker rm $(docker ps -aq)
使用数据卷
方式一 :直接使用命令来挂载 -v (volume) 指定路径挂载
docker run -v 主机目录:容器内目录
匿名挂载和具名挂载
匿名挂载就是不写主机目录,随机指定主机目录
docker run -v 容器内目录
具名挂载就是给卷起一个卷名(不是主机目录)
docker run -v 卷名:容器内目录
通过具名挂载可以用
docker volume inspect 卷名
来查看卷的信息
在容器内目录后加(:rw)或(:ro)可以定义卷的权限readwrite read-only
docker run -v 卷名:容器内目录:rw
配置环境
docker run -e 环境变量=值
查看容器信息
docker inspect 容器ID
runtime
容器创建需要:1、内核 2、runtime 3、管理工具
runtime 是容器真正运行的地方。runtime 需要跟操作系统 kernel 紧密协作,为容器提供运行环境,lxc、runc 和 rkt 是目前主流的三种容器 runtime。MANO使用的是runc 通过docker info可以查看。
runc 的管理工具是 docker engine。docker engine 包含后台 deamon 和 cli 两个部分。我们通常提到Docker,一般就是指的 docker engine。
docker内存限额:
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
-m 或 --memory:设置内存的使用限额,例如 100M, 2G。
–memory-swap:设置 内存+swap 的使用限额。
默认情况下,上面两组参数为 -1,即对容器内存和 swap 的使用没有限制
–vm 1:启动 1 个内存工作线程
–vm-bytes 280M:每个线程分配 280M 内存。
progrium/stress为镜像名称,如果–memory-swap不写,默认是memory的两倍
CPU限制:
Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
与内存限额不同,通过 -c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。
DockerFile
常用命令
FROM #基础镜镜像,一切从这里开始构建MAINTAINER #镜像是谁写的,姓名+邮箱RUN #镜像构建的时候需要运行的命令ADD 本机文件名 容器内目录 #构建镜像时添加的文件,Copy文件,自动解压COPY #类似ADD,将我们文件拷贝到镜像中WORKDIR #镜像的工作目录VOLUME ["/卷1",...] #通过VOLUME指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。EXPOSE #暴露端口配置CMD #容器启动时默认运行的命令,命令行中run命令指定了其他命令则会替换CMD,如果定义多个CMD只有最后一个会被执行ENTRYPOINT #与CMD类似,但是命令行中run命令不会被替换ENTRYPOINT,而是追加,可以与CMD联合使用,ENTRYPOINT设置执行的命令,CMD传递参数ONBUILD #当构建一个被继承DockerFile 这个时候就会运行ONBUILD的指令。触发指令。#设置子镜像的触发操作。构建镜像时,Docker的镜像构建器会将所有的ONBUILD指令指定的命令保存到镜像的元数据中,这些命令在当前镜像构建过程中不会执行。只有在新的镜像使用FROM指令指定父镜像为此镜像时,便会触发执行。ENV #构建的时候设置环境变量!ARG #构建的时候设置Dockerfile变量,不会带到镜像里!可以在构建镜像时设置 --build-arg ARG=..
CMD
设置的命令,可以在docker container run
时传入其它命令,覆盖掉CMD
的命令,但是ENTRYPOINT
所设置的命令时一定会被执行的。ENTRYPOINT
和CMD
可以联合使用,ENTRYPOINT
设置执行的命令,CMD传递参数。
构建ROS镜像实例
FROM ros:humble# 将sh改为bashRUN rm /bin/sh && ln -s /bin/bash /bin/sh# RVIZ的使用及其他图形化应用的使用ENV NVIDIA_VISIBLE_DEVICES ${ NVIDIA_VISIBLE_DEVICES:-all}ENV NVIDIA_DRIVER_CAPABILITIES ${ NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphicsENV DEBIAN_FRONTEND noninteractive# 换源RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak && \echo -e "deb https://repo.huaweicloud.com/ubuntu/ jammy main restricted universe multiverse\n\deb https://repo.huaweicloud.com/ubuntu/ jammy-updates main restricted universe multiverse\n\deb https://repo.huaweicloud.com/ubuntu/ jammy-backports main restricted universe multiverse\n\deb https://repo.huaweicloud.com/ubuntu/ jammy-security main restricted universe multiverse\n\deb https://mirrors.ustc.edu.cn/ubuntu/ jammy main restricted universe multiverse\n\deb https://mirrors.ustc.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse\n\deb https://mirrors.ustc.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse\n\deb https://mirrors.ustc.edu.cn/ubuntu/ jammy-security main restricted universe multiverse" \>/etc/apt/sources.list && \echo "deb [arch=$(dpkg --print-architecture)] http://repo.huaweicloud.com/ros2/ubuntu/ `lsb_release -cs` maindeb [arch=$(dpkg --print-architecture)] http://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu/ `lsb_release -cs` main" \>/etc/apt/sources.list.d/ros2-latest.list # 安装RUN apt update && apt install apt-utils && echo "source /opt/ros/humble/setup.bash" >>/root/.bashrcRUN apt install -y ros-${ ROS_DISTRO}-xacro ros-${ ROS_DISTRO}-rviz2 ros-${ ROS_DISTRO}-navigation2 ros-${ ROS_DISTRO}-nav2-bringup ros-${ ROS_DISTRO}-turtlebot3*
NVIDIA_VISIBLE_DEVICES
表示查看当前电脑或服务器上有的GPU,-all则是将宿主机上所有的GPU的环境变量设置到image中,使得image能够使用宿主机上的GPU
使用docker制作镜像过程中,在 apt-get 安装命令时,出现错误:
debconf: unable to initialize frontend: Dialogdebconf: (TERM is not set, so the dialog frontend is not usable.)debconf: falling back to frontend: Readlinedebconf: unable to initialize frontend: Readlinedebconf: (This frontend requires a controlling tty.)debconf: falling back to frontend: Teletypedpkg-preconfigure: unable to re-open stdin:
是因为在使用apt-get安装依赖时,可能会有对话框,制作镜像时如果不选择会导致失败。
解决方案:在Dockerfile中增加一句:ENV DEBIAN_FRONTEND noninteractive
Dockerfile 构建镜像
docker image build [OPTIONS] PATH |URL|
-f dockerfilename
-t list
or--tag list
Name and optionally a tag in the ‘name:tag’ format
查看镜像是如何通过DockerFile构建的
docker history 镜像
Docker网络
docker run 创建Docker容器时,可以用--net=选项
指定容器的网络模式:
host模式:
默认docker容器运行会分配独立的networknamspace
隔离子系统,基于host模式,容器将不会获得一个独立的networknamespace
,而是和宿主机共用一个network namespace
,容器将不会虚拟出自己的网卡等信息,而是使用宿主机的IP和端口。container模式:
其实container模式,其实就是容器之间共享一个networknamespace
,而不是和宿主机共享,也就是说新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享网络环境,同样,两个容器除了网络方面相同之外,其他的包括文件系统,进程列表等还是隔离的。None模式:
None模式与其他模式都不同,这种模式docker容器会拥有自己独立的networknamespace
,但是并不会为docker容器进行任何网络配置,也就是说,该docker容器没有网络信息,需要手动自定义等,我们可以借助pipwork工具为docker容器指定IP信息等;Bridge桥接模式:
bridge模式是docker默认的网络模式,该模式宿主机会为每一个容器自动分配一个networknamespace
,默认会将docker容器连接到一个虚拟网桥交换机docker0上。
#我们发现这个容器带来网卡,都是一对对的# evth-pair 就是一 对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连#正因为有这个特性,evth-pair 充当一个桥梁, 连接各种虚拟网络设备的# openstac, Docker容器之间的连接,OVS的连接, 都是使用evth-pair 技术
- Docker Bridge创建创建过程:
- 首先宿主机上创建一对虚拟网卡veth pair设备,veth设备总是成对出现的,形成一个通信通道,数据传输就是基于这个链路的,veth设备常用来连接两个网络设备
- Docker将veth pair设备的一端放在容器中,并命名为eth0,然后将另一端加入docker0网桥中,可以通过brctl show命令查看
- 从docker0网卡中分配一个IP到给容器使用,并设置docker0的IP地址为容器默认网关
- 此时容器IP与宿主机是可以通信的,宿主机也可以访问容器中的ip地址,在bridge模式下,连接同一网桥的容器之间可以相互通信,同时容器可以访问外网,但是其他物理机不能访问docker容器IP:需要通过NAT将容器的IP的port映射为宿主机的IP和port;
docker-compose
docker-compose是Docker官方的开源项目,不在docker中,要另外安装。
作用:批量容器编排
步骤:
- 用
Dockerfile
定义你的环境 - 定义Services需要的
docker-compose.yaml
- Run
docker-compose up
启动项目
实例
version: '2.3'services: nav2: # 指定当前服务(容器)依赖的服务 depend_on: - dp container_name: nav2 restart: always # 指定通过Dockerfile去构建镜像 build: . # 指定容器运行的镜像 image: long/nav2:humble # 覆盖容器启动后默认执行的命令 command: lxterminal # 覆盖容器默认的entrypoint entrypoint: ./setup.bash runtime: nvidia # 指定设备映射列表 devices: - "/dev/snd:/dev/snd" - "/dev/dri:/dev/dri" privileged: true stdin_open: true tty: true # 默认工作目录 working_dir: /root/nav2_ws # 添加环境变量 environment: - DISPLAY=unix$DISPLAY - QT_X11_NO_MITSHM=1 # 指定挂载数据卷 volumes: # 数据卷名称(卷标)或宿主机路径:容器中的路径:权限 - /tmp/.X11-unix:/tmp/.X11-unix:rw - /home/long/nav2_ws:/root/nav2_ws:rw - volume1:~/cache networks: - app_net # 设置网络连接模式 network_mode: host # 对外暴露的端口,格式 为 宿主:容器(HOST:CONTAINER) ports: - "8000:8000" - target: 80 #容器内的端口 published: 8080 #物理主机的端口 protocol: tcp #端口协议(tcp或udp) mode: host #host和ingress两种模式,host用于在每个节点上发布主机端口,ingress用于被负载平衡的swarm模式端口 # 暴露端口,但不映射到宿主机 expose: - "8000" entrypoint: ["echo 'hello'"] # 链接到另一个服务的容器 links: - # 链接到docker-compose.yml外部的容器 external_links: - # 配置容器连接的网络变量networks: #指定网络的名称,默认会创建bridge桥接网络 app_net: driver: custom-driver-1# 指定卷标(数据卷变量)volues: volume1:
docker-compose启用GPU访问
旧版
这通过使用服务属性runtime的使用,以提供对服务容器的GPU访问。但是,这不允许控制GPU设备的特定属性。
version: '2.3'services: test: image: nvidia/cuda:10.2-base command: nvidia-smi runtime: nvidia
新版
点我
进阶问题
docker 显示
/dev/snd是声卡系统
/dev/dri是 gazebo仿真
为什么需要DRI
http://www-x-wowotech-x-net.img.abc188.com/content/uploadfile/201512/5b56a76a97467a71495cd5b764b3ed4720151217141926.gif
在GUI环境中,一个Application想要将自身的UI界面呈现给用户,需要2个步骤:
根据实际情况,将UI绘制出来,以一定的格式,保存在buffer中。该过程就是常说的“Rendering”渲染。实际上就是生成图像数据的过程。
将保存在buffer中的UI数据,显示在display device上。该过程一般称作“送显”。
在操作系统中,Application不应该直接访问硬件,通常的软件框架是(从上到下):Application<---->Service<---->Driver<---->Hardware。这样考虑的原因主要有二:安全性和共享硬件资源(例如显示设备只有一个,却有多个应用想要显示)
Linux图形子系统包括如下的软件的软件模块:
3D-game engine、Applications和Toolkits,应用软件,其中3D-game engine是3D application的一个特例。
Display Server
图片给出了两个display server:Wayland compositor和X-Server(X.Org)。X-Server是linux系统在PC时代使用比较广泛的display server,而Wayland compositor则是新设计的,计划在移动时代取代X-Server的一个新的display server。
libX/libXCB和libwayland-client
display server提供给Application(或者GUI Toolkits)的、访问server所提供功能的API。libX/libXCB对应X-server,libwayland-client对已Wayland compositor。
libGL
libGL是openGL接口的实现,3D application(如这里的3D-game engine)可以直接调用libGL进行3D渲染。
libGL可以是各种不同类型的openGL实现,如openGL(for PC场景)、openGL|ES(for嵌入式场景)、openVG(for Flash、SVG矢量图)。
libGL的实现,既可以是基于软件的,也可以是基于硬件的。其中Mesa 3D是OpenGL的一个开源本的实现,支持3D硬件加速。
libDRM和kernel DRM
DRI(Direct Render Infrastructure)的kernel实现,及其library。X-server或者Mesa 3D,可以通过DRI的接口,直接访问底层的图形设备(如GPU等)。
KMS(Kernel Mode Set)
一个用于控制显示设备属性的内核driver,如显示分辨率等。直接由X-server控制。
Docker使用GPU
Docker 容器共享您主机的内核,但带有自己的操作系统和软件包。这意味着它们缺少用于与 GPU 交互的 NVIDIA 驱动程序。默认情况下,Docker 甚至不会向容器添加 GPU,因此docker run根本看不到您的硬件。
概括地说,让 GPU 工作是一个两步过程:在映像中安装驱动程序,然后指示 Docker 在运行时将 GPU 设备添加到容器中。
在继续进行 Docker 配置之前,请确保您的主机上的 NVIDIA 驱动程序正常工作。您应该能够成功运行nvidia-smi并看到您的 GPU 名称、驱动程序版本和 CUDA 版本。
要将 GPU 与 Docker 结合使用,首先要在主机安装NVIDIA Container Toolkit。这集成到 Docker 引擎中以自动配置您的容器以支持 GPU。
docker run -it --gpus all nvidia/cuda:11.4.0-base-ubuntu20.04 nvidia-smi
手动配置镜像
注意 Dockerfile 末尾的环境变量——这些定义了使用你的镜像的容器如何与 NVIDIA Container Runtime 集成:
ENV NVIDIA_VISIBLE_DEVICES allENV NVIDIA_DRIVER_CAPABILITIES compute,utility
一旦安装了 CUDA 并设置了环境变量,您的镜像应该会检测到您的 GPU。这使您可以更好地控制镜像的内容,但随着新 CUDA 版本的发布,您可能需要调整。
它是如何工作的?
NVIDIA Container Toolkit 是一个包的集合,它们将容器运行时(如 Docker)与主机上 NVIDIA 驱动程序的接口包装在一起。该libnvidia-container库负责提供 API 和 CLI,通过运行时包装器自动将系统的 GPU 提供给容器。
该nvidia-container-toolkit组件实现了一个容器运行时prestart钩子。这意味着它会在新容器即将启动时收到通知。它查看您要附加并调用libnvidia-container以处理容器创建的 GPU 。
挂钩由nvidia-container-runtime启用。这会包装您的“真实”容器运行时,例如 containerd 或 runc,以确保prestart运行NVIDIA挂钩。在钩子执行后,您现有的运行时会继续容器启动过程。安装容器工具包后,您将看到在 Docker 守护程序配置文件中选择了 NVIDIA 运行时。
权限问题
No protocol specified问题
这是由于X11服务默认只允许『来自本地的用户』启动的图形程序将图形显示在当前屏幕上。解决的办法很简单,允许所有用户访问X11服务即可。这个事情可以用xhost命令完成
在宿主机中运行
$ sudo apt-get install x11-xserver-utils$ xhost +
参数+
表示允许任意来源的用户,如果要指定docker的话,也可以运行以下命令:
$ xhost +local:docker
把用户添加进Docker用户组
使用docker的过程中,很多情况下都需要root权限才可以;为了避免多次使用sudo命令,故在此将当前用户添加到docker组;
# 添加docker用户组,一般已存在,不需要执行sudo groupadd docker# 将登陆用户加入到docker用户组中sudo gpasswd -a $USER dockersudo usermod -aG docker $USER#重启服务sudo service docker restart# 更新用户组newgrp docker# 测试docker命令是否可以使用sudo正常使用docker version