docker

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 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]
  1. -m--memory:设置内存的使用限额,例如 100M, 2G。

  2. --memory-swap:设置 内存+swap 的使用限额。

  3. 默认情况下,上面两组参数为 -1,即对容器内存和 swap 的使用没有限制

  4. --vm 1:启动 1 个内存工作线程

  5. --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所设置的命令时一定会被执行的。
  • ENTRYPOINTCMD 可以联合使用, 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 list or --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 指定。
  1. host模式:
    默认docker容器运行会分配独立的networknamspace隔离子系统,基于host模式,容器将不会获得一个独立的networknamespace,而是和宿主机共用一个network namespace,容器将不会虚拟出自己的网卡等信息,而是使用宿主机的IP和端口。

  2. container模式:
    其实container模式,其实就是容器之间共享一个networknamespace,而不是和宿主机共享,也就是说新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享网络环境,同样,两个容器除了网络方面相同之外,其他的包括文件系统,进程列表等还是隔离的。

  3. None模式:
    None模式与其他模式都不同,这种模式docker容器会拥有自己独立的networknamespace,但是并不会为docker容器进行任何网络配置,也就是说,该docker容器没有网络信息,需要手动自定义等,我们可以借助pipwork工具为docker容器指定IP信息等;

  4. Bridge桥接模式:
    bridge模式是docker默认的网络模式,该模式宿主机会为每一个容器自动分配一个networknamespace,默认会将docker容器连接到一个虚拟网桥交换机docker0上。

请添加图片描述

#我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
#正因为有这个特性,veth-pair 充当一个桥梁, 连接各种虚拟网络设备的
# openstack, Docker容器之间的连接,OVS的连接, 都是使用veth-pair 技术
  • Docker Bridge创建创建过程:
    1. 首先宿主机上创建一对虚拟网卡veth pair设备,veth设备总是成对出现的,形成一个通信通道,数据传输就是基于这个链路的,veth设备常用来连接两个网络设备
    2. Docker将veth pair设备的一端放在容器中,并命名为eth0,然后将另一端加入docker0网桥中,可以通过brctl show命令查看网桥(bridge)信息
    3. 从docker0网卡中分配一个IP到给容器使用,并设置docker0的IP地址为容器默认网关
    4. 此时容器IP与宿主机是可以通信的,宿主机也可以访问容器中的ip地址,在bridge模式下,连接同一网桥的容器之间可以相互通信,同时容器可以访问外网,但是其他物理机不能访问docker容器IP:需要通过NAT将容器的IP的port映射为宿主机的IP和port;

docker-compose

docker-compose是Docker官方的开源项目,不在docker中,要另外安装。

作用:批量容器编排

步骤:

  1. Dockerfile定义你的环境
  2. 定义Services需要的docker-compose.yaml
  3. 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个步骤:

  1. 根据实际情况,将UI绘制出来,以一定的格式,保存在buffer中。该过程就是常说的“Rendering”渲染。实际上就是生成图像数据的过程。

  2. 将保存在buffer中的UI数据,显示在display device上。该过程一般称作“送显”。
    在操作系统中,Application不应该直接访问硬件,通常的软件框架是(从上到下):Application<---->Service<---->Driver<---->Hardware。这样考虑的原因主要有二:安全性和共享硬件资源(例如显示设备只有一个,却有多个应用想要显示)

Linux图形子系统包括如下的软件的软件模块:

  1. 应用软件
    如3D-game engine、Applications和Toolkits,其中3D-game engine是3D application的一个特例。

  2. Display Server
    图片给出了两个display server:Wayland compositor和X-Server(X.Org)。X-Server是linux系统在PC时代使用比较广泛的display server,而Wayland compositor则是新设计的,计划在移动时代取代X-Server的一个新的display server。

  3. libX/libXCB和libwayland-client
    display server提供给Application(或者GUI Toolkits)的、访问server所提供功能的API。libX/libXCB对应X-server,libwayland-client对已Wayland compositor。

  4. 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硬件加速。

  5. libDRM和kernel DRM
    DRI(Direct Render Infrastructure)的kernel实现,及其library。X-server或者Mesa 3D,可以通过DRI的接口,直接访问底层的图形设备(如GPU等)。

  6. 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shilong Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值