胜人者有力,自胜者强。


导航


壹-概念介绍

一个发行的Ubuntu操作系统主要是由两部分组成:Linux内核+Ubuntu套件,其中内核和套件是解耦合的,套件的功能主要包含 软件管理方式apt-get、服务管理方式systemd 等。而不同厂家对套件亦各有不同的理解,于是基于Linux衍生出了很多的操作系统发行版本,如Ubuntu、CentOS、Debian等。

根据以上的理解,那么在一台Linux机器上灵活替换套件,从而实现一机多套件体验的想法是不是也可以实现呢?实际上Docker镜像技术正是利用了这一点。

在Docker架构中,镜像就是类似于套件(如ubuntu 操作系统发行版)的存在,可以在任何满足要求的 Linux 内核之上运行,而镜像的类型也不止局限于操作系统可以是承载于操作系统之上的服务软件、应用软件。如基于Debian 镜像在其中安装 MySQL 5.6,那我们可以将其命名为 Mysql:5.6 镜像。此时Docker 镜像的层级概念就体现出来了,底层一个 Debian 操作系统镜像,上面叠加一个 mysql 层,就完成了一个 mysql 镜像的构建,而Debian 操作系统镜像也被称为 mysql 镜像层的父镜像。

那么镜像最后的作用是什么呢?很好理解,回到 Linux 内核上来运行,通过镜像来运行时我们常常将提供的环境称为容器。容器是一个动态的环境,每一层镜像中的文件属于静态内容,然而 Dockerfile 中的 ENV、VOLUME、CMD 等内容最终都需要落实到容器的运行环境中,而这些内容均不可能直接坐落到每一层镜像所包含的文件系统内容中,那此时每一个 Docker 镜像还会包含 json 文件来记录与容器之间的关系。

镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层(存储层的数据可以被读写,而镜像层的数据只能被读取)。

Docker镜像原理,见下图:
image

Dockerfile、镜像、容器、远端仓库、本地存档之间的关系,见下图:
image


貳-命令使用

Docker命令语法说明,见下图:
image

备注:docker [ subcommand ] help 可查看命令或子命令之下的其它功能命令;docker [ subcommand ] [ cmd ] -h 可查询功能命令更详细的参数用法,以及显示该命令是否存在别名命令。


叁-网络模式

  1. bridge 模式(--net=bridge):【默认模式】此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。(相当于VM中的仅主机模式,该模式下的容器均处在同一个网段之中)

  2. host 模式(--net=host):容器不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。(相当于应用服务直接运行于宿主机之上)

  3. container 模式(--net=container:NAME_or_ID):新容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。(相当于应用服务直接运行于另一个容器之上)

  4. none 模式(--net=none):该模式关闭了容器的网络功能。(相当于没有网卡的虚拟机)

  5. 参考链接


肆-镜像构建

  1. 镜像构建的方式有2种:基于容器的docker commit、基于基础镜像的docker build。【但通常不会使用commit在容器中定制镜像,因为在容器中即便是执行一些很简单的命令都会导致大量的无关内容被添加进来,这将会导致镜像极为臃肿(个人觉得:build的过程其实也就是commit的过程,只需要将臃肿的文件删除之后再提交即可)。另外使用 docker commit 意味着对镜像的所有操作都是黑箱操作,生成的镜像也被称为 黑箱镜像(就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知),这对于维护工作是很不友好的。所以commit的使用通常是一些特殊场景,如被入侵后保存现场等。】

  2. 基础镜像 scratch:该镜像是一个空白镜像,对于在Linux下静态编译的程序来说,由于并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。一般对那些通过Go开发的应用制作镜像会使用这种方式。

  3. 镜像构建上下文:常见的构建命令docker build -t nginx:v3 . 中的‘.’并非指Dockerfile文件所在的路径而是构建镜像上下文路径,构建时docker 客户端会将上下文路径中的文件全部打包发送给docker服务端,服务端收到后会展开这个包然后依据Dockerfile文件中的类似的ADD、COPY等指令将指令中所需的文件添加到镜像中去。这也就是为什么Dockerfile文件中相关的文件路径都是相对路径而不能是绝对路径,因为这个路径都是相对于服务端解包后的文件夹路径。【构建命令参考docker build -f ../Dockerfile  -t nginx:v3 /build_dir/ 】

  4. manifest 的作用:使用镜像创建一个容器,那么该镜像必须与 Docker 宿主机系统架构一致才能被正常使用,此时通过镜像名区分不同系统架构的镜像便可解决此问题,但这样做很繁琐。此时 镜像的manifest便发挥了作用:当用户获取一个镜像时,Docker 引擎会首先查找该镜像是否有 manifest 列表,如果有的话引擎会按照 Docker 宿主机运行环境(系统及架构)查找出对应镜像,如果没有的话才会直接获取镜像。【username/test镜像 manifest 构建命令:docker manifest create username/test  username/x8664-test username/arm64v8-test【创建】;docker manifest annotate username/test username/x8664-test --os linux --arch x86_64【设置】;docker manifest inspect username/test【查看】;docker manifest push username/test【上传】】

构建管理命令说明【docker buildx [cmd]】:

  • build:开始构建

  • stop:停止构建

  • du:显示构建过程中的缓存占用空间

  • prune:清除缓存占用空间

Dockerfile 指令详解

  • COPY 指令:将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。

  • ADD 指令:和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能,如 <源路径> 可以是一个 URL

  • CMD 指令:用于指定容器主进程默认的启动命令,且该命令可在启动容器时被覆盖。【注意:在指定了 ENTRYPOINT 指令后,CMD 指令则被用来指定具体的参数。】

  • ENTRYPOINT 指令:和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

  • ENV 指令:就是设置环境变量而已,无论是后面的其它指令如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

  • ARG 指令:和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的是构建镜像环境时的环境变量,在将来容器运行时是不会存在这些环境变量的。

  • VOLUME 指令:可以事先指定某些目录挂载为匿名卷,这样容器在运行时如果用户不指定挂载,其应用也可以正常运行。VOLUME 在运行时可被替代。【容器的数据读写默认发生在容器的存储层,当容器被删除时其上的数据将会丢失,因此我们应该尽量保证容器存储层不发生写操作。mysql镜像一般会使用匿名卷用以保存它的数据库数据,这样可保证数据迁移复用。】

  • EXPOSE 指令:是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。【声明端口的好处:一是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;二是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。】

  • WORKDIR 指令:可以来指定工作目录,以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。【默认情况下,每条RUN都会产生新的容器环境,上个环境的工作目录并不会继承到下个环境中去。】

  • USER 指令:和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

  • LABEL 指令:用来给镜像以键值对的形式添加一些元数据(其实就是备注信息)。

  • SHELL 指令:可以指定 RUN ENTRYPOINT CMD 指令的 shell,Linux 中默认为 ["/bin/sh", "-c"]

  • ONBUILD 指令:是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

  • HEALTHCHECK 指令:是告诉 Docker 应该如何进行判断容器的状态是否正常。【在没有 HEALTHCHECK 指令前,Docker 引擎只能通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。如,HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1】


伍-容器编排

在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况,此时便只能通过命令行依序逐个启动容器,而每个容器在启动时所需要的参数一般也各不相同,于是记忆各种启动参数以及逐个启动容器使得Docker体验非常差。而 Compose 恰好满足了这样的需求,它允许用户通过一个单独的 docker-compose.yml 模板文件定义一组相关联的应用容器为一个项目。

Compose中的2个重要概念:服务(一个应用的容器)、项目(由一组关联的应用容器组成的一个完整业务单元)。在通过CLI docker compose [cmd] -f docker-compose.yml 管理项目时,大部分 cmd 命令作用的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。

编排管理命令说明【docker compose [cmd]】:

  • up:该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

  • down:停止up启动的所有容器,并移除网络(创建的容器是否也被移除,下次up再重新创建?)。

  • stop:停止已经处于运行状态的所有容器,但不删除它们。

  • start:启动已经存在的容器。

  • images:列出 Compose 文件中包含的镜像。

  • exec、run:进入指定的容器或在指定的容器执行命令。

  • config:验证 Compose 文件格式是否正确。

  • build、pull:提前将Compose 文件中需要构建的、依赖拉取的镜像操作到位。

Compose 顶级元素:

  • name、version:指定项目名称及当前 compose 的版本。

  • services:指定服务容器启动时的相关参数。

  • networks:创建服务相互访问的网络环境。

  • volumes:创建可持续性数据存储的卷。

  • configs:与卷一样,configs作为文件被挂载到服务容器的文件系统中,以使服务的配置文件可灵活变换。

  • secrets:机密提供了一种更安全的方式来将敏感信息引入应用程序的服务

  • build、deploy:提供从源代码重新构建应用程序。

  • 各顶级元素官方指令详解

  • Docker Compose 语法在线生成工具composerize:支持将docker 容器启动命令转换为compose的格式。

示例应用配置模板,见下图:
image


陆-杂项

  1. Docker 图形化管理工具DockerUI的容器docker.ui 挂载文件/var/run/docker.sock的原因:该sock文件是由Docker守护进程默认监听的Unix域套接字,容器内的进程可以通过它与Docker守护进程进行通信,继而实现容器内应用可以控制外部Docker实现对镜像/容器的管理。

  2. 一个容器中可以运行多个应用,但不符合单一原则(即一个容器只运行一个主进程)。使用方法就是:通过将多个应用的启动程序写入脚本以后台静默运行的方式进行启动即可。

  3. Docker镜像是由一系列镜像层来构成的,每层代表Dockerfile中的一条指令。当拉取镜像时,如果本地已经存在相同的镜像层,那么这些层就可以被复用,不需要再次下载。这样可以大大提高镜像拉取的速度,并节省磁盘空间。【镜像层拉取的方式同git很像:先获取镜像概要请求,再比对不同,然后拉取不同。】

  4. 所创建卷在宿主机的路径位置:/var/lib/docker/volumes/*/_data/

  5. docker image save 和docker image load的关系:save可将本地仓库中的镜像进行导出作为tar文件本地存档,以供load可进行离线导入镜像。【导出的tar文件内容是分层的文件系统,即多层只读的镜像层

  6. docker container export 和 docker image import 和 docker container commit 的关系:export可将容器当前的文件系统根目录文件递归全部导出,然后import可将其导入用以创建一个镜像,该镜像中会保留容器之前运行中产生的所有文件。而docker container commit就相当于将export和import这两个动作合二为一。【导出的tar文件内容是一个完整的Linux系统目录结构,即单层可读写的存储层