概念1.镜像（Image）：类似于虚拟机中的镜像，是一个包含有文件系统的面向Docker引擎的只读模板。2.容器（Container）：类似于一个轻量级的沙盒，可以将其看作一个极简的Linux系统环境（包括root权限、进程空间、用户空间和网络空间等），以及运行在其中的应用程序。3.仓库（Repository）：类似于代码仓库，这里是镜像仓库，是Docker用来集中存放镜像文件的地方。Docker镜像的分类1.基础镜像，可以去docker.io上下载，也可以在国内的Docker仓库下载2.自定义镜像，可以基于基础镜像实现镜像的自定义Docker镜像的相关命令1.docker images2.docker search centos3.docker pull centos:7Docker仓库的配置/etc/docker/daemon.json，重启Docker{ "registry-mirrors": ["http://hub-mirror.c.163.com/"]}国内仓库pull镜像docker pull hub-mirror.c.163.com/library/centos:7docker images镜像导出备份，删除和导入重命名：docker tag hub-mirror.c.163.com/library/centos:7 centos:7导出镜像：docker save hub-mirror.c.163.com/library/centos:7 >/tmp/centos.tar删除镜像：docker rmi centos:7镜像导入：docker load < /tmp/centos7.tarDocker 容器可以使用镜像生成对应运行的容器，一个镜像可以生成多个容器Centos7镜像生成的容器系统是Centos7，Ubuntu镜像生成的容器系统是Ubuntu的使用Centos7镜像启动容器docker run -it centos:7 /bin/bashi表示交互式，t表示打开一个Shell窗口宿主机上查看容器的相关操作1.docker ps：查看运行的容器。docker ps -a：查看所有容器2.docker inspect：查看容器详细信息3.docker logs：查看容器日志4.docker rm：删除容器，docker rm -f：强制删除容器容器后台运行的特点如果没有永久运行的程序，终端一退出容器就会马上退出容器永久运行的条件：需要有永久运行的程序，并且使用run -d后台启动容器启动后台容器：docker run -d centos:7 /bin/bash -c "while true;do echo helloworld; sleep 5; done"进入后台容器：docker exec -it xxx /bin/bash后台容器的停止停止后台容器：docker stop xxx 或者 docker kill xxx批量删除容器：docker rm -f xxx xxx进入容器后ctrl+p+q可以退出终端而不关闭容器，也可以直接关闭终端，容器中pid为1的进程只要不被杀死，容器就不会被关闭。自定义镜像容器的临时性1.容器里的操作当容器删除了就没了2.最好不要把数据存储在容器里可将宿主机文件挂载到docker中，或者使用docker数据卷操作 参见docker数据卷Docker自定义镜像一般自带的镜像无法满足特定的要求，需要基于基础镜像来自定义Docker镜像Docker镜像制作的两种方法1.基于Docker Commit制作镜像2.基于Dockerfile制作镜像，Dockerfile方式为主流制作镜像的方式Docker Commit给基础镜像新增ifconfig命令docker run --name helloworld -it centos /bin/bashyum install net-tools -y保存为镜像docker commit xx（容器名称） myimage:v1.0docker images参考51 CTO 2019Docker入门实战视频
一个docker容器启动之后，我们进入可以看到一个操作系统的所有文件。我们可以通过chroot这个命令可以更改一个程序运行时的根目录。假设，我们现在有一个 $HOME/test 目录，想要把它作为一个 /bin/bash 进程的根目录。首先，创建一个 test 目录和几个 lib 文件夹：$ mkdir -p $HOME/test $ mkdir -p $HOME/test/{bin,lib64,lib} $ cd $T然后，把 bash 命令拷贝到 test 目录对应的 bin 路径下：$ cp -v /bin/{bash,ls} $HOME/test/bin接下来，把 bash 命令需要的所有 so 文件，也拷贝到 test 目录对应的 lib 路径下。$ T=$HOME/test $ list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')" $ for i in $list; do cp -v "$i" "${T}${i}"; done最后，执行 chroot 命令，告诉操作系统，我们将使用 $HOME/test 目录作为 /bin/bash 进程的根目录：$ chroot $HOME/test /bin/bash这时，你如果执行 "ls /"，就会看到，它返回的都是 $HOME/test 目录下面的内容，而不是宿主机的内容。这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统，就是所谓的“容器镜像”。它还有一个更为专业的名字，叫作：rootfs（根文件系统）。Docker容器运行过程启用 Linux Namespace 配置；设置指定的 Cgroups 参数；切换进程的根目录（Change Root）。
Cgroup和Namespace类似，也是将进程进行分组，但它的目的和namespace不一样，Namespace是为了隔离进程组之间的资源，而Cgroup是为了对一组进程进行统一的资源监控和限制。它最主要的作用，就是限制一个进程组能够使用的资源上限，包括 CPU、内存、磁盘、网络带宽等等。在Linux中，Cgroups给用户暴露出来的接口是文件系统，以文件与目录形式组织在/sys/fs/cgroup路径之下。root@herefree:/sys/fs/cgroup# ls blkio cpu,cpuacct freezer net_cls perf_event systemd cpu cpuset hugetlb net_cls,net_prio pids unified cpuacct devices memory net_prio rdmacpu 子系统，主要限制进程的 cpu 使用率。cpuacct 子系统，可以统计 cgroups 中的进程的 cpu 使用报告。cpuset 子系统，可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。memory 子系统，可以限制进程的 memory 使用量。blkio 子系统，可以限制进程的块设备 io。devices 子系统，可以控制进程能够访问某些设备。net_cls 子系统，可以标记 cgroups 中进程的网络数据包，然后可以使用 tc 模块（traffic control）对数据包进行控制。net_prio — 这个子系统用来设计网络流量的优先级freezer 子系统，可以挂起或者恢复 cgroups 中的进程。ns 子系统，可以使不同 cgroups 下面的进程使用不同的 namespacehugetlb — 这个子系统主要针对于HugeTLB系统进行限制，这是一个大页文件系统。如何使用？在对应子系统下面创建一个目录。root@herefree:/sys/fs/cgroup/cpu# mkdir container root@herefree:/sys/fs/cgroup/cpu# cd container/ root@herefree:/sys/fs/cgroup/cpu/container# ls cgroup.clone_children cpuacct.usage_percpu_sys cpu.shares cgroup.procs cpuacct.usage_percpu_user cpu.stat cpuacct.stat cpuacct.usage_sys notify_on_release cpuacct.usage cpuacct.usage_user tasks cpuacct.usage_all cpu.cfs_period_us cpuacct.usage_percpu cpu.cfs_quota_us后台写一个死循环脚本，运行起来 while : ; do : ; done &查看cpu占用使被该进程组限制的进程每100ms时间只能使用20ms的CPU时间。echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us将被限制进程的PID写入到container组里的task文件。echo 11036 > /sys/fs/cgroup/cpu/container/tasks 再次查看对于 Docker 等 Linux 容器项目来说，它们只需要在每个子系统下面，为每个容器创建一个控制组（即创建一个新目录），然后在启动容器进程之后，把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。
假设我们有了一个Docker项目，我们创建一个容器。$ docker run -it ubuntu /bin/bash-it 参数告诉了 Docker 项目在启动容器后，需要给我们分配一个文本输入 / 输出环境，也就是 TTY，跟容器的标准输入相关联，这样我们就可以和这个 Docker 容器进行交互了。而 /bin/bash 就是我们要在 Docker 容器里运行的程序。所以上面这条指令的意思就是：请帮我启动一个容器，在容器里执行 /bin/sh，并且给我分配一个命令行终端跟这个容器交互。我们在容器中输入ps指令：/ # ps PID USER TIME COMMAND 1 root 0:00 /bin/sh 2 root 0:00 ps在这里可以看到，我们在 Docker 里最开始执行的 /bin/sh，就是这个容器内部的第 1 号进程（PID=1），而这个容器里一共只有两个进程在运行。这就意味着，前面执行的 /bin/sh，以及我们刚刚执行的 ps，已经被 Docker 隔离在了一个跟宿主机完全不同的世界当中。我们在宿主机上运行/bin/bash程序时，操作系统会给它分配一个进程编号pid。这个进程编号就是进程的唯一标识，我们在docker中运行/bin/bash时，给它施展了一个“障眼法”，让它看不到其他的进程，这样它就会自己认为自己的pid=1。这种机制，其实就是对被隔离应用的进程空间做了手脚，使得这些进程只能看到重新计算过的进程编号，这就是Linux里面的Namespace机制。Namespace是对全局系统资源的一种封装隔离，使得处于不同namespace的进程拥有独立的全局系统资源，改变一个namespace中的系统资源只会影响当前namespace里的进程，对其他namespace中的进程没有影响。目前，Linux内核里面实现了7种不同类型的namespace。名称 宏定义 隔离内容 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)PID Namespace在 Linux 系统中创建进程的系统调用是 clone()int pid = clone(main_function, stack_size, SIGCHLD, NULL);这个系统调用就会为我们创建一个新的进程，并且返回它的进程号 pid。我们用 clone() 系统调用创建一个新进程时，就可以在参数中指定 CLONE_NEWPID 参数，比如：int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 这时，新创建的这个进程将会“看到”一个全新的进程空间，在这个进程空间里，它的 PID 是 1。https://segmentfault.com/a/1190000006908272
容器是一种沙盒技术，它可以像集装箱一样，将应用“装”起来，这样应用与应用之间就有了边界不相互干扰。也可以被方便的搬来搬去。这个边界是如何实现的呢？假如，现在你要写一个计算加法的小程序，这个程序需要的输入来自于一个文件，计算完成后的结果则输出到另一个文件中。由于计算机只认识 0 和 1，所以无论用哪种语言编写这段代码，最后都需要通过某种方式翻译成二进制文件，才能在计算机操作系统中运行起来。而为了能够让这些代码正常运行，我们往往还要给它提供数据，比如我们这个加法程序所需要的输入文件。这些数据加上代码本身的二进制文件，放在磁盘上，就是我们平常所说的一个“程序”，也叫代码的可执行镜像（executable image）。首先，操作系统从“程序”中发现输入数据保存在一个文件中，所以这些数据就被会加载到内存中待命。同时，操作系统又读取到了计算加法的指令，这时，它就需要指示 CPU 完成加法操作。而 CPU 与内存协作进行加法计算，又会使用寄存器存放数值、内存堆栈保存执行的命令和变量。同时，计算机里还有被打开的文件，以及各种各样的 I/O 设备在不断地调用中修改自己的状态。一旦“程序”被执行起来，它就从磁盘上的二进制文件，变成了计算机内存中的数据、寄存器里的值、堆栈中的指令、被打开的文件，以及各种设备的状态信息的一个集合。像这样一个程序运起来后的计算机执行环境的总和，就是进程。容器技术的核心功能，就是通过约束和修改进程的动态表现，从而为其创造出一个“边界”。对于 Docker 等大多数 Linux 容器来说，Cgroups 技术是用来制造约束的主要手段，而 Namespace 技术则是用来修改进程视图的主要方法。
docker数据卷（数据挂载）1.引言docker的镜像是由多个只读的文件系统叠加在一起形成的。当我们在我启动一个容器的时候，docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件，那么这个文件将会从只读层复制到读写层。该文件的只读版本还在，只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时，之前的更改将会消失。在Docker中，只读层及在顶部的读写层的组合被称为Union File System（联合文件系统）。为了很好的实现数据保存和数据共享，Docker提出了Volume这个概念，简单的说就是绕过默认的联合文件系统，而以正常的文件或者目录的形式存在于宿主机上。又被称作数据卷。摘自：https://www.cnblogs.com/lishanlei/p/9503596.html2.Docker数据管理docker在容器中管理数据主要有两种方式：数据卷（Volumes）挂载主机目录（Bind mounts）2.1数据卷数据卷是一个可供一个或多个容器使用的特殊目录，它绕过UFS,可以提供很多有用的特性：数据卷可以在容器之间共享和重用对数据卷的修改会立马生效对数据卷的更新，不会影响镜像数据卷默认会一直存在，即使容器被删除Docker中提供了两种挂载方式，-v和-mount创建数据卷docker volume create mydata查看所有数据卷docker volume ls查看数据卷信息docker volume inspect mydata注：Mountpoint为数据在本机存储的位置，如果磁盘存储空间不足可修改此位置挂载方式一：docker run --name xxxx -p 8888:8888 -v /my:/docker -it imagename /bin/bash--name： 为容器起名字-p ：宿主机端口：docker端口 （端口映射）-v ：宿主机目录：docker目录 （必须为绝对路径）方式二：docker run --name xxxx -p 8888:8888 --mount type:volume,source=/src/xxx,target=/xxx /my:/docker -it imagename /bin/bashtype选项，其可以是bind，volume，或 tmpfs。本主题讨论卷，因此类型始终是 volume注意：使用-v参数时如果本地目录不存在Docker会自动为你创建一个文件夹。使用--mount参数时如果本地目录不存在，Docker会报错。Docker挂载主机目录的默认权限是读写，用户也可以通过增加readonly指定为只读。如果挂载一个空的数据卷到容器中的一个非空目录中，那么这个目录下的文件会被复制到数据卷中。(我的测试：使用 -v 参数并没有这个效果，需要使--mount参数，如果不符请指正)如果挂载一个非空的数据卷到容器中的一个目录中，那么容器中的目录中会显示数据卷中的数据。如果原来容器中目录非空，那么这些原始数据会被隐藏掉。2.2挂载主机目录docker run -it --name c1 -v /宿主机目录:/docker目录 -it imagename /bin/bash参考：https://cloud.tencent.com/developer/article/1491692https://www.jianshu.com/p/19f12c616d0c