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 run 参数 镜像名称:tag 执行的命令
参数
-p <port:port>:端口映射,第一个port是本机的端口,第二个port是Docker容器的端口-i:保持和docker 容器内的交互,启动容器时,运行的命令结束后,容器依然存活,没有退出(默认是会退出,即停止的)-t:为容器的标准输入虚拟一个tty-d:后台运行容器--name string:给容器起一个自定义名称--rm:容器在启动后,执行完成命令或程序后就销毁
运行模式
attached模式
前台运行
detached模式
后台运行
开启方法:参数-d或者--detach
detached模式转换为attached模式
docker attach <ID or ImageName>
交互模式
直接进入交互模式
docker exec -it <ID or Image name> 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 load [OPTIONS]
# docker load -i image.tar
OPTIONS说明:
- –input,-i:指定导入的文件,带起STDIN
- –quiet,-q:精简输出信息
导入容器
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
停用全部运行中的容器
$ 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 --vm 1 --vm-bytes 280M [image_name]
-
-m或--memory:设置内存的使用限额,例如 100M, 2G。 -
--memory-swap:设置 内存+swap 的使用限额。 -
默认情况下,上面两组参数为 -1,即对容器内存和 swap 的使用没有限制
-
--vm 1:启动 1 个内存工作线程 -
--vm-bytes 280M:每个线程分配 280M 内存。
[image_name]为镜像名称,如果--memory-swap不写,默认是memory的两倍
CPU限制:
Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
与内存限额不同,通过 -c 设置的 cpu shares 并不是 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改为bash
RUN 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,}graphics
ENV 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` main
deb [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 -y && apt install apt-utils -y && echo "source /opt/ros/humble/setup.bash" >> /root/.bashrc
RUN 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: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
dpkg-preconfigure: unable to re-open stdin:
是因为在使用apt-get安装依赖时,可能会有对话框,制作镜像时如果不选择会导致失败。
解决方案:在Dockerfile中增加一句:ENV DEBIAN_FRONTEND noninteractive
Dockerfile 构建镜像
docker image build [OPTIONS] PATH |URL|
-f dockerfilename-t listor--tag list
Name and optionally a tag in the ‘name:tag’ format
查看镜像是如何通过DockerFile构建的
docker history 镜像
Docker网络
我们在使用docker run创建Docker容器时,可以用 --net选项指定容器的网络模式,Docker可以有以下4种网络模式:
- host模式:使用
--net=host指定。 - none模式:使用
--net=none指定。 - bridge模式:使用
--net=bridge指定,默认设置。 - container模式:使用
--net=container:NAME_or_ID指定。
-
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上。

#我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
#正因为有这个特性,veth-pair 充当一个桥梁, 连接各种虚拟网络设备的
# openstack, Docker容器之间的连接,OVS的连接, 都是使用veth-pair 技术
- Docker Bridge创建创建过程:
- 首先宿主机上创建一对虚拟网卡veth pair设备,veth设备总是成对出现的,形成一个通信通道,数据传输就是基于这个链路的,veth设备常用来连接两个网络设备
- Docker将veth pair设备的一端放在容器中,并命名为eth0,然后将另一端加入docker0网桥中,可以通过
brctl show命令查看网桥(bridge)信息 - 从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
- 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
新版
安装nvidia-container后还报错: Error response from daemon: could not select device driver “nvidia” with capabilities: [[gpu]]
解决办法:在/etc/docker/daemon.json中加入以下内容
{
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-runtime": "nvidia"
}
docker声音
/dev/snd 是 Linux 系统中的一个目录,它代表 Sound Resource Interface(声音资源接口)。这个目录包含了一些文件,用于管理声音设备。这些文件主要是针对音频处理器的。
在 Linux 系统中,声音设备通常是由音频处理器处理的。音频处理器负责处理声音文件和播放音频。为了与音频处理器交互,Linux 系统使用 ALSA(Advanced Linux Sound Architecture)标准。/dev/snd 目录就是用来存储与 ALSA 相关的信息的。
/dev/snd 目录下的每个文件都是一个设备节点,用于表示一个特定的音频设备。每个文件都有一个唯一的编号,用于标识不同的音频设备。用户可以通过读取这些文件来获取与音频处理器相关的信息,例如获取设备属性、查询驱动版本等。
要使用 /dev/snd 目录下的文件,用户需要有特定的权限。通常,只有 root 用户和音频组(audio)用户可以访问这个目录。要给普通用户访问 /dev/snd 目录的权限,需要编辑 /etc/group 文件。
例如,要将用户 username 添加到音频组,可以执行以下命令:
sudo usermod -a -G audio username
现在,username 用户应该可以访问 /dev/snd 目录了。
docker显示
/dev/dri 是 Linux 系统中的一个目录,它代表Display Resource Interface(显示资源接口)。这个目录包含了一些文件,用于管理显示设备。这些文件主要是针对 GPU(图形处理器)的。
在 Linux 系统中,显示设备通常是由 GPU 处理的。GPU 负责处理屏幕上的图形和动画。为了与 GPU 交互,Linux 系统使用 DRM(Direct Response Metadata)标准。/dev/dri 目录就是用来存储与 DRM 相关的信息的。
/dev/dri 目录下的每个文件都是一个设备节点,用于表示一个特定的 GPU 设备。每个文件都有一个唯一的编号,用于标识不同的 GPU 设备。例如/dev/dri/card0代表第一块图形处理器。用户可以通过读取这些文件来获取与 GPU 相关的信息,例如获取设备属性、查询驱动版本等。
要使用 /dev/dri 目录下的文件,用户需要有特定的权限。通常,只有 root 用户和视频组(video)用户可以访问这个目录。要给普通用户访问 /dev/dri 目录的权限,需要编辑 /etc/group 文件。
例如,要将用户 username 添加到视频组,可以执行以下命令:
sudo usermod -a -G video username
现在,username 用户应该可以访问 /dev/dri 目录了。
显示所需的组件

在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 all
ENV 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 docker
sudo usermod -aG docker $USER
#重启服务
sudo service docker restart
# login新用户组
newgrp docker
# 测试docker命令是否可以使用sudo正常使用
docker version
974

被折叠的 条评论
为什么被折叠?



