docker关键知识点

3 篇文章 0 订阅
3 篇文章 0 订阅

一、虚拟机VS容器

  

  一)虚拟机的缺点及容器为何产生

  • 资源占用多
  • 冗余步骤多,繁琐
  • 启动慢

  因为虚拟机存在上面的缺点,于是Linux发展出了另一种虚拟化技术:Linux容器(Linux container,缩写为LXC)。

  Linux容器不是模拟一个完整的操作系统 ,而是对进程进行隔离。

  有了容器,就可以将软件运行所需要的所有资料打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需要的库资源和设置。

  二)docker和虚拟机之间的不同之处

  1、传统虚拟机

  传统虚拟机技术是虚拟出一整套硬件后,在其上运行一个完整的操作系统,在该系统上再运行所需要的应用进程

1、主要是因为每个虚拟机需要运行自己的一组系统进程,这就产生了除组件进程外消耗以外的额外计算资源损耗。

2、不同虚拟机它拥有了完全不同的操作系统

3、在虚拟机之下是宿主机的操作系统与一个管理程序,它将物理硬件资源分成较小部分的虚拟硬件资源,从而被每个虚拟机里的操作系统使用。
注意:存在两种类型的管理程序:第一种类型的管理程序不会使用宿主机OS,而第二种类型会

  2、容器

  容器内的应用进程直接运行在宿主机的内核,容器内没有自己的内核,而且也没有进行硬件虚拟 。因此容器要比传统虚拟机更为轻便。    

  每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会互相影响,能区分计算资源,耦合度低。

  Docker 安装时会自动在 host 上创建三个网络:bridge、host和none

    • none 网络就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,可以通过 --network=none 指定使用 none 网络。
    • 连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过 --network=host 指定使用 host 网络。
      • docker host的网络最大的好处就是性能,若容器对网络传输效率有较高要求,则可以选择host网络
    • Docker 安装时会创建一个 命名为 docker0 的 linux bridge。如果不指定--network,创建的容器默认都会挂到 docker0 上
      • 使用brctl show显示出来
容器更加轻量级,它允许在相同的硬件上运行更多数量的组件。

一个容器仅仅是运行在宿主机上被隔离的单个进程,仅消耗应用容器消耗的资源,不会消耗其他进程的开销

多个容器则会完全执行运行在宿主机上的同一个内核的系统调用,此内核是唯一一个在宿主机操作系统上执行x86指令的内核。CPU也不需要再做任何对虚拟机能做那样的虚拟化。
     1)启动时间

  docker启动是秒级的,传统虚拟机启动是分钟级的;另外docker是一个精简版、高度浓缩的小型Linux系统。 

  • docker通过类似Git设计理念的操作来方便用户获取、分发和更新应用镜像,存储复用,增量更新
  • docker通过dockerfile支持灵活的自动化创建和部署机制,提高工作效率,使流程标准化
    2)运行在不同环境的应用

  

   3、docker容器技术与传统虚拟机技术比较

    

特性容器虚拟机
启动速度快,秒级慢,分钟级
性能接近原生较弱
内存代价很小较多
占用磁盘空间小,一般为MB非常大,一般为GB
运行密度单机支持上千个容器一般几十个
运行状态直接运行在宿主机的内核上,不同容器共享同一个Linux内核运行于Hypervisor上
隔离性完全隔离完全隔离
迁移性优秀一般
资源利用率

   隔离的内容:文件系统、网络、PID、etc、usr、UTS(UTS命名空间是Linux内核Namespace(命名空间)的一个子系统,主要用来完成对容器HOSTNAME和domain的隔离,同时保存内核名称、版本、以及底层体系结构类型等信息)

  虚拟机的好处:它提供的是完全的隔离的环境,因为每个虚拟机运行在它自己的内核上;

  容器:它都是调用一个内核,这存在安全隐患

  建议:

  1. 若你的硬件资源有限,那当你有少量进程需要隔离时,虚拟机就可以成为一个选项
  2. 为了在同一台机器上运行大量被隔离的进程,容器因它的低消耗而成为一个更好的选择
  4、为什么docker比虚拟机快?

  虚拟机运行它自己的一组系统服务,而容器则不会,因为他们都运行在同一个操作系统上。(运行一个容器不会像虚拟机那样开机,它的进程可以很快启动)

  1. docker有着比虚拟机更少的抽象层。由于docker不需要hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的是实际物理机的硬件资源。因此在cpu、内存利用率上docker将会在效率上有明显的而优势;
  2. docker利用的是宿主机的内核,而不需要guest os。因此当建立一个容器时,docker不需要和虚拟机一样重新加载一个操作系统的内核。从而避免加载操作系统内核返回比较费时的资源过程,当新建一个虚拟机时,虚拟机软件需要加载guest os,返回新建过程是分钟级的。而docker由于直接利用宿主机的操作系统,则省略了加载过程,因此新建一个docker容器只需要几秒。

  三)容器实现隔离机制

目录

  1、限制
  有两个机制可用:
第一个是 隔离namespace命名空间, 它使每个进程只看到它自己的系统视图(文件、进程、网络接口、主机名等);
第二个是 限制cgroups控制组 (control groups),它限制了进程能使用的资源量 (CPU、 内存、 网络带宽等)。 

  默认情况下,每个Linux系统最初仅有一个命名空间。所有系统资源(诸如文件系统、用户ID、网络接口等)属于这一个命名空间。但是你能创建额外的命名空间,以及在他们之间组织资源。对于一个进程,可以在一个命名空间中运行它。进程将只能看到同一个命名空间下的资源。当然,会存在多种类型的命令空间。所以一个进程不单单属于某一个命名空间,而属于每个类型的一个命名空间。

    1)Linux内核里面实现了7种不同类型的命名空间
名称        宏定义(系统调用参数)      隔离内容
Cgroup      CLONE_NEWCGROUP              Cgroup root directory (since Linux 4.6)
IPC         CLONE_NEWIPC                 信号量、消息队列和共享内存System V IPC, POSIX message queues (since Linux 2.6.19)
Network     CLONE_NEWNET                 网络设备、网络栈、端口等Network devices, stacks, ports, etc. (since Linux 2.6.24)
Mount       CLONE_NEWNS                  挂载点(文件系统)Mount points (since Linux 2.4.19)
PID         CLONE_NEWPID                 进程编号Process IDs (since Linux 2.6.24)
User        CLONE_NEWUSER                用户和用户组User and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTS         CLONE_NEWUTS                 主机名与域名Hostname and NIS domain name (since Linux 2.6.19)
      不同类型的命名空间的作用
  1. mount(mnt):每个进程都存在于一个mount Namespace里面,mount Namespace为进程提供了一个文件层次视图。如果不设定这个flag,子进程和父进程将共享一个mount Namespace,其后子进程调用mount或umount将会影响到所有该Namespace内的进程。如果子进程在一个独立的mount Namespace里面,就可以调用mount或umount建立一份新的文件层次视图。
  2. process ID(pid):linux通过命名空间管理进程号,同一个进程,在不同的命名空间进程号不同!进程命名空间是一个父子结构,子空间对于父空间可见。
  3. network(net):Network Namespace为进程提供了一个完全独立的网络协议栈的视图。包括网络设备接口,IPv4和IPv6协议栈,IP路由表,防火墙规则,sockets等等。一个Network Namespace提供了一份独立的网络环境,就跟一个独立的系统一样
  4. inter-process communication(ipc):用于隔离进程间通讯所需的资源( System V IPC, POSIX message queues),PID命名空间和IPC命名空间可以组合起来用,同一个IPC名字空间内的进程可以彼此看见,允许进行交互,不同空间进程无法交互
  5. UTS:用于隔离主机名
  6. user ID(user):用于隔离用户

  每种命名空间被用来隔离一组特定的资源。例如:UTS命名空间决定了运行在命名空间里的进程能看见哪些主机名和域名。通过分派两个不同的UTS命名空间给一对进程,能给他们看见不同的本地主机名。换句话说,这两个进程就好像正在两个不同的机器上运行一样(只是就主机名而言是这样的)

  同样,一个进程属于什么network命名空间决定了运行在进程里的应用程序能看见什么网络接口。每个网络接口属于一个命名空间,但是可以从一个命名空间转移到另一个。每个容器都使用它自己的网络命名空间,因此每个容器仅能看见他自己的一组网络接口。

  2、资源限制

  对容器进行限制。防止容器无限制滥用甚至耗尽宿主机上的资源。而 Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。

  Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。

  在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。在 Ubuntu 16.04 机器里,我可以用 mount 指令把它们展示出来,这条命令是

mount -t cgroup 
cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct)
blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
...

  可以看到,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法。比如,对 CPU 子系统来说,我们就可以看到如下几个配置文件,这个指令是:

ls /sys/fs/cgroup/cpu
cgroup.clone_children 
cpu.cfs_period_us 
cpu.rt_period_us 
cpu.shares notify_on_releasecgroup.procs 
cpu.cfs_quota_us 
cpu.rt_runtime_us 
cpu.stat 
tasks

  以上输出的关键文件 cfs_periodcfs_quota, 可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。

  而这样的配置文件又如何使用呢?
  你需要在对应的子系统下面创建一个目录,比如,我们现在进入 /sys/fs/cgroup/cpu 目录下:

root@ubuntu:/sys/fs/cgroup/cpu$ mkdir container
root@ubuntu:/sys/fs/cgroup/cpu$ ls container/
cgroup.clone_children 
cpu.cfs_period_us 
cpu.rt_period_us cpu.shares 
notify_on_releasecgroup.procs 
cpu.cfs_quota_us 
cpu.rt_runtime_us 
cpu.stat tasks

  这个目录就称为一个“控制组”。你会发现,操作系统会在你新创建的 container 目录下,自动生成该子系统对应的资源限制文件。

  现在,我们在后台执行这样一条脚本

$ while : ; do : ; done &
[1] 226

  显然,它执行了一个死循环,可以把计算机的 CPU 吃到 100%,根据它的输出,我们可以看到这个脚本在后台运行的进程号(PID)是 226。

  这样,我们可以用 top 指令来确认一下 CPU 有没有被打满:

$ top
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

  在输出里可以看到,CPU 的使用率已经 100% 了(%Cpu0 :100.0 us)。

  而此时,我们可以通过查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):

$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us 
100000

  接下来,我们可以通过修改这些文件的内容来设置限制。

  比如,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us):

$ echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us

  结合前面的介绍,你应该能明白这个操作的含义,它意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽。

接下来,我们把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

$ echo 226 > /sys/fs/cgroup/cpu/container/tasks 

  我们可以用 top 指令查看一下:

$ top
%Cpu0 : 20.3 us, 0.0 sy, 0.0 ni, 79.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

  可以看到,计算机的 CPU 使用率立刻降到了 20%(%Cpu0 : 20.3 us)。

  除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  • blkio:为​​​块​​​设​​​备​​​设​​​定​​​I/O 限​​​制,一般用于磁盘等设备
  • cpuset:为进程分配单独的 CPU 核和对应的内存节点
  • memory:为进程设定内存使用的限制

  Linux Cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。 对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。

  而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了,比如这样一条命令:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

  在启动这个容器后,我们可以通过查看 Cgroups 文件系统下,CPU 子系统中,“docker”这个控制组里的资源限制文件的内容来确认:

$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us 
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us 
20000

  这就意味着这个 Docker 容器,只能使用到 20% 的 CPU 带

  四)容器的创建

  1、容器创建需要
  • 内核
  • runtime:容器真正运行的地方。runtime需要跟操作系统kernl紧密协作,为容器提供运行环境,lxc、runc和rkt是目前主流的三种容器runtime
  • 管理工具:runc的管理工具是docker engine。docker engine包含后台deamon和cli两个部分。我们通常提到docker,一般指的docker engineZ

   

  2、容器资源限制

#内存限制
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M

1、-m 或 --memory:设置内存的使用限额,例如 100M, 2G。

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

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

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

5、--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 总和的比例


# block IO权重

Block IO 是另一种可以限制容器使用的资源。Block IO 指的是磁盘的读写,docker 可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽

默认情况下,所有容器能平等地读写磁盘,可以通过设置 --blkio-weight 参数来改变容器 block IO 的优先级。
--blkio-weight 与 --cpu-shares 类似,设置的是相对权重值,默认为 500。在下面的例子中,container_A 读写磁盘的带宽是 container_B 的两倍。

# 限制 bps 和 iops    

bps 是 byte per second,每秒读写的数据量。

iops 是 io per second,每秒 IO 的次数。

可通过以下参数控制容器的 bps 和 iops:

--device-read-bps,限制读某个设备的 bps。

--device-write-bps,限制写某个设备的 bps。

--device-read-iops,限制读某个设备的 iops。

--device-write-iops,限制写某个设备的 iops。   

                                                                                                                                                                                                                                                                                                                                                                                                         

二、docker与虚拟化

  一)虚拟化概述

  虚拟化技术是通用的概念,在不同的领域有不同的理解。在计算领域,一般是指计算虚拟化,或通常说的服务器虚拟化。

  虚拟化是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构件的不可分割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。

  虚拟化的核心是对资源的抽象,目标往往是为了在同一个主机上同时运行多个系统或应用。从而提高资源的利用率,并带来降低成本、方便管理和容错容灾等好处。

  二)虚拟化分类

  https://www.cnblogs.com/sammyliu/articles/4389765.html

  docker以及其他容器技术,都属于操作系统虚拟化这个范畴。操作系统虚拟化最大的特点是不需要额外的supervisor支持。

  传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统层。docker容器是在操作系统层面实现虚拟化,直接复用本地主机的操作系统,因此更加轻量级。

三、docker的关键知识点

  一)docker的版本说明

  docker版本的CE才是开源版,EE是企业版。

  从2017年第一季度开始,docker版本号遵循YY.MM-xx格式,类似于Ubuntu等项目。例如 2018年6月第一次发布的社区版本为18.06.0-ce

  二)docker容器本质

  一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。这也是容器技术中一个非常重要的概念,即:容器是一个“单进程”模型。

  • 容器其实就是Linux下一个特殊的进程
  • docker容器通过namespace实现进程隔离,通过cgroup实现资源限制
  • docker镜像(rootfs)是一个操作系统的所有文件和目录而不包括内核,docker镜像是共享宿主机的内核的
  • docker镜像是以主副方式挂载,所有的增删改都只会作用在容器层,但是相同的文件会覆盖掉下一层,这种方式也被称为“copy-on-wtite”

  三)docker的三要素

  1、镜像(image)

  一个 只读 的模板。 镜像可以用来创建docker容器,一个镜像可以创建很多容器 。

  镜像的特点: 镜像都是只读的。当容器启动时,一个新的可写层被加载到镜像的顶部。这一层被称为容器层,容器层之下的层都是镜像层。

  2、容器(container)

  独立运行的一个或者一组应用。容器是利用镜像创建的运行实例(相对于Python中的类和对象的概念)。

  它可以被启动、开始、停止、删除。每个容器都是互相隔离的,保证安全的平台。

  可以把容器看做是一个简易版的Linux环境 (包括root用户名权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

  容器的定义和镜像几乎是一模一样的,也是一堆层的统一视角, 唯一区别的是容器的最上面那一层是可读写的。

  3、仓库(repository)

  仓库(repository)和仓库注册服务器(registry)是有区别的。仓库注册服务器上往往放着很多个仓库,每个仓库中又包含了很多个镜像,每个镜像有不同的标签(tag)。

  仓库分为公开仓库(public)和私有仓库(private)两种形式。

  四)UnionFS(联合文件系统)

  UnionFS(联合文件系统):union文件系统(unionFS)是一种分层、轻量级并且高性能的文件系统,它支持 对文件系统的修改作为一次提交来一层层的叠加 ,同时可以将不同的目录挂载到同一个虚拟文件系统下。

  union文件系统是docker镜像的基础。镜像可以通过分层来进行继承。基于基础镜像(没有父镜像),可以制作各种的应用镜像。 

  特性:一次同时加载多个文件系统,但从外面看来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录 

  五)docker加载原理

  docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统称为联合文件系统(unionFS)。 

  bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux刚启动时会加载bootfs文件系统, 在docker镜像的最底层就是bootfs 。这一层与我们典型的linux/unix系统是一样的,包含boot加载器和内核。当boot加载完成之后,整个内核就都在内存中了。此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。 

  rootfs(root file system),在bootfs之上,包含的就是典型的linux系统中的/dev/,/proc,/bin,/etc/等标准目录和文件。rootfs就是各种不同操作系统发行版,比如ubuntu,centos等。

  六)docker的五种存储方式

  详细内容见:https://www.cnblogs.com/fengjian2016/p/6638205.html

  七)docker的四种网络模式

  1. host模式,使用--net=host指定。
  2. container模式,使用--net=container:NAME_or_ID指定。
  3. none模式,使用--net=none指定。
  4. bridge模式,使用--net=bridge指定,默认设置。
  1、host模式

  使用--net=host指定,容器和宿主机共享network namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

  使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好


    

  2、container模式

  使用--net=container:NAME_or_ID指定,容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。

  新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信

  

  3、none模式

  使用--net=none指定,容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。也就是这个容器没有网卡、IP、路由等。需要我们自己为容器添加网卡、配置IP。

  这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过--network=none来指定。优势:这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

   

  4、bridge模式

  使用--net=bridge指定,默认设置。

  当docker启动后,会在主机上创建一个名为docker0的虚拟网桥,此主机上的docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

  从docker0子网中分批额一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一堆虚拟网卡veth pair设备,docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxx这样的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。

  bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看

     

  八)支持的三种数据持挂载方式

  docker提供了三种不同的方式将数据从宿主机挂载到容器中,volume、bind mount、tmps mount

  • bind mount:可以存储在宿主机系统的任意位置
    • 例:docker run -v /opt/html:/usr/share/nginx/html -p 81:80 -d --name nginx_bind nginx:latest
    • 缺点:被挂载的宿主机目录(或文件)不受保护,任何容器都可以取随意修改
    • 注意:若使用bind mounts挂载宿主机目录到一个容器中的非空目录,那么此容器中的非空目录中的文件会被隐藏,容器只能访问到的文件均来自宿主机目录
  • volume:docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)

docker volume create nginx-volume
docker volume ls
docker run --mount type=volume,source=nginx-volume,destination=/usr/share/nginx/html,readonly -p 82:80 -d --name nginx_volume nginx:latest

  若强制删除容器后,数据卷不会被删除,还是会保存在宿主机的docker/volumes目录下

  • tmpfs mounts:挂载存储在宿主机系统的内存中,不会写入宿主机的文件系统
    • docker run --mount type=tmpfs,destination=/usr/share/nginx/html -p 83:80 -d --name nginx_tmpfs nginx:latest

  

  对比docker三种挂载方式
docker三种挂载方式对比
bind(-v)volumetmpfs
volume位置可指定任意位子$(docker_data_dir)/docker/volumes/...宿主机内存中
对已有 mount point影响隐藏并替换为volume原有数据复制到volume
是否支持单个文件支持不支持,只能是目录
权限控制可设置为只读,默认为读写权限可设置为只读,默认为读写权限
移植性移植性弱,与host path绑定移植性强,无须指定host目录
是否支持持久化支持支持不支持
应用场景

主机和容器共享配置文件(docker默认情况下,通过这种方式为容器提供DNS解析,将/etc/resolv.conf挂载到容器中)

多个运行容器间共享数据

备份、恢复或将数据从一个docker迁移到另一个docker主机

既不想将数据存在宿主机中,也不想存于容器中(出于安全考虑,或当演员需要些大量非持久性的状态数据时为了保护容器的性能)

  Bind 模式无法很好地解决多跨宿主机共享存储的问题、Bind 模式的管理问题等。

  提出 Volume 的最核心的目的提升Docker对不同存储介质的支撑能力,这同时也可以减轻Docker本身的工作量。存储不仅有挂载在宿主机上的物理存储,还有网络存储,Docker 抽象出了存储启动(Sotroage Driver)来去解决对网络存储的读写问题

  九)docker的应用场景

  • web应用的自动化打包发布
  • 自动化测试和持续集成、发布
  • 在服务型环境中部署调整数据库或其他的后台应用
  • 从头编译或扩展现有的OpenShift或cloud Foundry平台来搭建自己的PaaS环境

四、安装指定版本docker

1、查看系统要求
Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看CentOS的内核版本。
uname -a

2、删除旧版本
yum remove docker  docker-common docker-selinux docker-engine

3、安装需要的软件包
yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

4、设置Docker yum源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

5、查看所有仓库中所有docker版本
可以查看所有仓库中所有docker版本,并选择特定的版本安装。

yum list docker-ce --showduplicates | sort -r

6、安装docker
sudo yum install docker-ce
由于repo中默认只开启stable仓库,故这里安装的是最新稳18.03.0.ce-1.el7.centos。

如果要安装特定版本:
sudo yum install docker-ce-18.06.1.ce
  
7、启动
设置为开机启动
systemctl enable docker
启动
systemctl start docker
查看启动状态
systemctl status docker
查看版本

docker version

五、docker相关命令

  docker官方文档:https://docs.docker.com/engine/reference/run/

  

  一)docker帮助命令

docker info #查看docker相关的信息
docker version #查看安装docker的版本信息
docker help #docker命令的帮助信息

  二)docker 镜像相关的命令

docker images #列出本地的所有镜像
docker search imagesname/imageid #搜索镜像 注意,即使你配置了阿里云加速,docker search命令查找的网站默认还是 https://hub.docker.com。阿里云加速只是下载时才会被用到。 -s starts超过多少的镜像
docker pull imagesname/imageid #下载镜像 -s starts超过多少的镜像
docker rmi imagesname/imageid #删除镜像,默认基于这个镜像还有正在运行的镜像是删除不了的,需要加上-f参数强制删除
删除多个:docker rmi -f 镜像1:tag 镜像2:tag,不写tag,删除的就是latest 
删除全部:docker rmi -f $(docker images -qa)
docker save 命令可以将镜像保存为归档文件:docker save alpine | gzip > alpine-latest.tar.gz
docker load  命令可以将保存的镜像加载到本地docker里面:docker load -i alpine-latest.tar.gz
docker tag #给镜像打标签 docker tag mysql:5.7.22 docker-registry:5000/mysql:5.7.22

  三)docker 容器相关的命令

  1、以交互性启动容器:docker run -it
docker run -it
 --name='容器新名字':为容器指定一个别名;
 -d:后台运行容器,并返回容器ID,也就是启动守护式容器;
 -i:以交互式模式运行容器,通常与-t同时使用;
 -t:tty,为容器重新分配一个伪终端,通常与-i同时使用;
 -P:随机端口映射;
 -p:指定端口映射,有以下四种格式:
 -v /宿主机绝对路径目录:/容器内目录 镜像名  

  镜像添加存储卷

1、查看数据卷是否挂载成功
docker inspect 8ad4df9ec2fd     

2、验证容器和宿主机之间数据共享 
    在/myDataVolume和/dataVolumeContainer上各创建文件,都能互相看到。

3、容器停止退出后,主机修改后数据是否同步 
    答案:还同步 

4、带权限的数据卷 
    命令:docker run -it -v /宿主机绝对路径目录:/容器内目录:ro  镜像名 
    说明:-v是volume卷的意思 
    宿主机绝对目录和容器内目录都不用提前建立
    ro:是read only的意思 
  2、查看容器运行情况:docker ps

  参数

-a:列出当前所有正在运行的容器+历史上运行过的;
-l:last,显示最近创建的容器;
-n:显示最近n个创建的容器;
-q:静默模式,只显示容器编号
--no-trunc:不截断输出
-d 以守护式方式启动的容器
  3、查看容器日志
命令格式:docker logs -f -t --tail 容器id 
参数说明: 
    -t是加入时间戳 
    -f是跟随最新的日志打印 
    --tail是Linux命令,表示显示最后多少条 

docker logs -t --help

Usage: docker logs [OPTIONS] CONTAINER

Fetch the logs of a container

Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
--tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)

  4、查看容器内的进程
命令格式:docker top 容器id 
  5、查看容器内的细节

  以json形式返回

命令格式:docker inspect 容器id 
  6、进入正在运行的容器并以命令行交互 

  以下两种方式

1 docker exec -it 容器id bash shell 
2 docker attach 容器id

  docker exec与docker attach的区别

  • attach:直接进入容器启动命令的终端,不会启动新的进程;
    • 当多个窗口同时用attach命令连到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。
  • exec:是在容器中打开新的终端,并且可以启动新的进程。
    • 通过指定-it参数来保持标准输入打开,并且分配一个伪终端。通过exec命令对容器进行操作是最推荐的方式。
  7、从容器内拷贝文件到宿主机上 
命令格式:docker cp 容器id或容器名:容器内路径 目的宿主机路径

  应用场景:当我们以前台交互式方式运行容器后,如果在容器里面执行exit操作,容器就会停止,此时容器中运行的数据也就没有了。这时我们就需要把运行中的容器数据拷贝到宿主机上来保留。 

  8、从宿主机上拷贝文件到容器内
命令格式:docker cp 宿主机路径  容器id或容器名:容器内路径
  9、容器生命周期管理
docker stop imagename/imageid #停止容器
docker start imagename/imageid  #启动容器
docker restart imagename/imageid #重启容器
docker kill  imagename/imageid  #强制停止容器
docker rm imagename/imageid #删除容器 -f强制删除正在容器
  10、批量操作容器和镜像

  减少工作量,一劳永逸的方法就是将痛苦提前,先思考如何批量删除,以后就安装文本,直接操作。

  可以知道删除 docker container 和 docker image 的关键都是找到准确的 ID。如果能批量提供 ID 号给删除命令,就能实现批量删除了。

  批量获取容器和镜像的ID

批量获取容器的ID
docker ps -a -q
或
docker container ls -aq

批量获取镜像的ID
docker image ls -aq
7c03076402d9
7ae4e0670a3f

  批量删除本机所有容器

docker rm -rf $(docker ps -aq)
docker ps -a -q |xargs docker rm
docker  rm  $(docker  container  ls -aq)

   批量删除本机所有镜像

docker rmi $(docker image ls -aq)
docker rmi $(docker images -q)

  如果只想批量删除一部分容器或者镜像

将要删除的容器名写到一个文件中,然后根据提供的名字,再结合 grep 、awk 等命令,就可以轻松地获取准确的 ID 号了。只要获取了 ID 号,就可以用上面的方法将它们删除。

  按条件删除镜像

  没有打标签

docker rmi `docker images -q | awk '/^<none>/ { print $3 }'`
  镜像名包含关键字

docker rmi --force `docker images | grep doss-api | awk '{print $3}'`    //其中doss-api为关键字
  11、将容器打成新的镜像
docker commit -m "change somth" -a "somebody info" container_id(docker ps -a获取id) 新镜像名字
  12、进入node容器可实时查看当前运行容器负载状态
docker stats ef6dceff2557| grep -viE "disk|oss|nas|csi|POD|kube|node-exporter"

  四)docker save与docker export的区别

  1、docker save

  docker save是用来将一个或多个image打包保存的工具。

docker save -o images.tar postgres:9.6 mongo:3.4

  docker save可以指定image,可以指定container,docker save将保存的是容器背后的image。

  将打包的镜像导入,若本地存在同名的镜像会覆盖

docker load -i images.tar

  应用场景:如果你的应用是使用docker-compose.yml编排的多个镜像组合,但你要部署的客户服务器并不能连外网。这时,你可以使用docker save将用到的镜像打个包,然后拷贝到客户服务器上使用docker load载入。

  2、docker export

  docker export是用来将container的文件系统进行打包的(只能指定container)

docker export -o postgres-export.tar postgres

  将打包的container载入进来使用docker import,可以指定tag

docker import postgres-export.tar postgres:latest

  注意:

  1. docker import将container导入后会成为一个image,而不是恢复为一个container。
  2. 如果本地镜像库中已经存在同名的镜像,则原有镜像的名称将会被剥夺,赋给新的镜像。原有镜像将成为孤魂野鬼,只能通过IMAGE ID进行操作。

  docker export的应用场景主要用来制作基础镜像:比如你从一个ubuntu镜像启动一个容器,然后安装一些软件和进行一些设置后,使用docker export保存为一个基础镜像。然后,把这个镜像分发给其他人使用

  3、docker save和docker export的区别
  1. docker save保存的是镜像(image),docker export保存的是容器(container);
  2. docker load用来载入镜像包,docker import用来载入容器包,但两者都会恢复为镜像;
  3. docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称。

  五)docker 的prune清理资源

  1、docker system df 查看资源信息,RECLAIMABLE是可回收比例
# docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              291                 41                  101.3GB             93.2GB (92%)
Containers          194                 65                  5.274GB             5.257GB (99%)
Local Volumes       1                   1                   0B                  0B
Build Cache         0                   0                   0B                  0B

  查看帮助信息

docker system df -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker system df [OPTIONS]

Show docker disk usage

Options:
      --format string   Pretty-print images using a Go template
  -v, --verbose         Show detailed information on space usage  ##查看详情
  2、docker system prune

  查看帮助信息

# docker system prune -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker system prune [OPTIONS]

Remove unused data

Options:
  -a, --all             Remove all unused images not just dangling ones
      --filter filter   Provide filter values (e.g. 'label=<key>=<value>')
  -f, --force           Do not prompt for confirmation
      --volumes         Prune volumes
  清理磁盘,删除关闭的容器、无用的数据卷和网络,以及旧的镜像(无tag的镜像) -f免交互

  在 Docker 17.06.1 及更高版本中必须为 docker system prune 命令明确指定 --volumes 标志才会修剪卷。

]# docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N] 
  清理得更加彻底,可以将没有容器使用Docker镜像都删掉
# docker system prune -a
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all images without at least one container associated to them
  - all build cache

Are you sure you want to continue? [y/N]

  3、清理镜像
  清理none镜像 Prune命令
  none镜像的产生和困惑

我们偶尔会看到 none镜像(虚悬镜像),那是因为

  1. 构建镜像过程中因为脚本错误导致很多镜像构建终止,产生很多none标签的版本
  2. 手动构建镜像的时候没有进行提交,遗留来的垃圾镜像
  3. 这些镜像占据较大的存储空间,需要删除
  清理none镜像(虚悬镜像)
命令: docker image prune
默认情况下,docker image prune 命令只会清理 虚无镜像(没被标记且没被其它任何镜像引用的镜像
  清理无容器使用的镜像
命令: docker image prune -a

  默认情况下,系统会提示是否继续。要绕过提示,请使用 -f 或 --force 标志。

  4、清理容器

  停止容器后不会自动删除这个容器,除非在启动容器的时候指定了 –rm 标志。使用 docker ps -a 命令查看 Docker 主机上包含停止的容器在内的所有容器。你可能会对存在这么多容器感到惊讶,尤其是在开发环境。停止状态的容器的可写层仍然占用磁盘空间。要清理掉这

docker images prune -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker images [OPTIONS] [REPOSITORY[:TAG]]

List images

Options:
  -a, --all             Show all images (default hides intermediate images)
      --digests         Show digests
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print images using a Go template
      --no-trunc        Don't truncate output
  -q, --quiet           Only show numeric IDs

  默认情况下,所有停止状态的容器会被删除。可以使用 --filter 标志来限制范围。例如,下面的命令只会删除 24 小时之前创建的停止状态的容器:  

  5、清理卷
# docker volume prune -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker volume prune [OPTIONS]

Remove all unused local volumes

Options:
      --filter filter   Provide filter values (e.g. 'label=<label>')
  -f, --force           Do not prompt for confirmation

  6、清理网络

  Docker 网络不会占用太多磁盘空间,但是它们会创建 iptables 规则,桥接网络设备和路由表条目。要清理这些东西,可以使用 docker network prune 来清理没有被容器未使用的网络。

# docker network prune -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker network prune [OPTIONS]

Remove all unused networks

Options:
      --filter filter   Provide filter values (e.g. 'until=<timestamp>')
  -f, --force           Do not prompt for confirmation

六、dockerfile保留字指令

  http://blog.itpub.net/28916011/viewspace-2213324/

  一)自定义镜像时,建议思考一下几点

  • 精简镜像用途:尽量让每个镜像的用途比较集中、单一,避免构造大而复杂、多功能的镜像
  • 选用合适的基础镜像:过大的基础镜像会造成生成臃肿的镜像,一般推荐较为小巧的debian镜像
  • 提供足够清晰的命令注释和维护者信息:dockerfile也是一种代码,需要考虑方便后面扩展和他人使用
  • 正确的使用版本号:使用版本号信息,如1.0,2.0,而非latest,将避免内容不一致可能引发的惨案
  • 减少镜像层数:若希望所生成的镜像层数尽量少,则要尽量合并指令,例如多个RUN指令可以合并成一条
  • 及时删除临时文件和缓存文件:特别是在执行apt-get指令后,/var/cache/apt下面会缓存一些安装包
  • 提高生成速度:如合理使用缓存,减少内容目录下的文件,或使用.dockerignore文件指定等
  • 调整合理的指令顺序:在开启缓存的情况下,内容不变的指令尽量放在前面,这样可以复用
  • 减少外部源的干扰:若确认需要从外部引入数据,需要指定持久的地址,并带有版本信息,让他人可以重复而不出错

  二)操作系统基础镜像

  BusyBox、Alphine、Debian/Ubuntu、CentOS等

  选择操作系统基础镜像需要注意:

  • 官方镜像体积都比较小,之带有一些基本的组件。精简的系统有利于安全、稳定和高效运行,也适合进行定制
  • 个别第三方镜像(如tutum,已被docker收购),质量也非常高。这些镜像通常针对于应用进行配置。
  • 处于安全考虑,几乎所有官方制作的镜像几乎没有安装SSH服务,无法使用用户名和密码直接登录

  注意点:

  1. Dockfile中可以有多个CMD指令,但只有最后一个生效。
  2. ADD与COPY的区别:本地目录为源目录
    1. ADD src可以为URL;若是tar文件,会自动解压到dest路径下
    2. COPY只是复制,推荐使用COPY
  3. HEALTHCHECK健康检查
  4. 使用.dockerignore文件来让docker忽略匹配模块路径下的目录和文件(每一行添加一条匹配模式)

七、容器在生产环境实践

  注意:
  1. 若docker出现不可控的风险,是否考虑到了备选的解决方案
  2. 是否需要对docker容器进行资源限制,以及如何限制(如CPU、内存、网络、磁盘等)
  3. docker对容器的安全管理做的不够完善,在应用到生产环境之前可以使用第三方工具来加强容器的安全管理。如使用apparmor对容器的能力进行限制、使用更加严格的iptable规则、禁止root登录、限制普通用户权限以及做好系统日志的记录
  4. 公司内部私有仓库的管理、镜像的管理问题是否解决。目前官方提供的私有仓库管理工具功能并不十分完善。harbor了解一下

  一)问题汇总

  1、解决镜像无法删除的问题multiple repositories
Error response from daemon: conflict: unable to delete ea5f89e79b1e (must be forced) - image is referenced in multiple repositories

意思是说,存在镜像多个引用,即同一个image id有多个repo。需要注意,自己是否真的确定要删除!

可以通过docker rmi   $REPO/$NAME:$VERSION方式删除。

  二)扩展知识点

  1、如何查看docker容器的启动命令
1.安装runlike
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py    # 运行安装脚本
pip install runlike 

2.执行命令 runlike -p 容器ID
  2、docker以root身份登录容器
# 前言
在部署服务的过程中,会遇到进到的容器内部,不是以root的身份,如果我们需要进行在容器内部执行命令,就会出现权限的问题,比如:如下显示

> bash-4.2$ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime          
- cp: cannot create regular file ‘/etc/localtime’: Permission denied

#### 解决办法
以root身份进入容器内部,命令如下:
> docker exec --privileged -u root -it 容器名字/容器id /bin/bash{sh}(bash{sh})
  3、 查看构建docker镜像的完整命令(dockerfile每个步骤内容)
# 查看构建镜像的完整命令
docker history centos:7 --no-trunc

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值